Skip to content

Commit 5bfa644

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

1 file changed

Lines changed: 118 additions & 42 deletions

File tree

host/hackrf-tools/src/hackrf_transfer.c

Lines changed: 118 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,50 @@ 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+
for (uint8_t i = 0; i < precision; i++) {
347+
n *= 10;
348+
char c = '0' + (n >> Qn);
349+
*p++ = c;
350+
n &= mask;
351+
}
352+
353+
// trim trailing zeros
354+
while (p > str->data && p[-1] == '0') {
355+
--p;
356+
}
357+
*p = '\0';
358+
359+
return str->data;
360+
}
361+
362+
char* frequency_fp64toa(uint64_t value, t_fp64toa* str)
363+
{
364+
return fp64toa(24, value, str);
365+
}
366+
367+
char* sample_rate_fp64toa(uint64_t value, t_fp64toa* str)
368+
{
369+
return fp64toa(36, value, str);
370+
}
371+
322372
static volatile bool do_exit = false;
323373
static volatile bool interrupted = false;
324374
static volatile bool tx_complete = false;
@@ -351,13 +401,16 @@ struct timeval time_start;
351401
struct timeval t_start;
352402

353403
bool automatic_tuning = false;
354-
int64_t freq_hz;
404+
uint64_t freq_hz;
405+
fp_40_24_t freq_fp_hz;
355406

356407
bool if_freq = false;
357-
int64_t if_freq_hz;
408+
uint64_t if_freq_hz;
409+
fp_40_24_t if_freq_fp_hz;
358410

359411
bool lo_freq = false;
360-
int64_t lo_freq_hz = DEFAULT_LO_HZ;
412+
uint64_t lo_freq_hz = DEFAULT_LO_HZ;
413+
fp_40_24_t lo_freq_fp_hz = FREQ_FP_HZ(DEFAULT_LO_HZ);
361414

362415
bool image_reject = false;
363416
uint32_t image_reject_selection;
@@ -369,7 +422,8 @@ bool antenna = false;
369422
uint32_t antenna_enable;
370423

371424
bool sample_rate = false;
372-
uint32_t sample_rate_hz;
425+
fp_28_36_t sample_rate_fp_hz;
426+
uint64_t sample_rate_hz;
373427

374428
bool force_ranges = false;
375429

@@ -778,17 +832,20 @@ int main(int argc, char** argv)
778832
break;
779833

780834
case 'f':
781-
result = parse_frequency_i64(optarg, endptr, &freq_hz);
835+
result = parse_frequency_fp(optarg, endptr, &freq_fp_hz);
836+
freq_hz = FP_FREQ_HZ(freq_fp_hz);
782837
automatic_tuning = true;
783838
break;
784839

785840
case 'i':
786-
result = parse_frequency_i64(optarg, endptr, &if_freq_hz);
841+
result = parse_frequency_fp(optarg, endptr, &if_freq_fp_hz);
842+
if_freq_hz = FP_FREQ_HZ(if_freq_fp_hz);
787843
if_freq = true;
788844
break;
789845

790846
case 'o':
791-
result = parse_frequency_i64(optarg, endptr, &lo_freq_hz);
847+
result = parse_frequency_fp(optarg, endptr, &lo_freq_fp_hz);
848+
lo_freq_hz = FP_FREQ_HZ(lo_freq_fp_hz);
792849
lo_freq = true;
793850
break;
794851

@@ -820,7 +877,8 @@ int main(int argc, char** argv)
820877
break;
821878

822879
case 's':
823-
result = parse_frequency_u32(optarg, endptr, &sample_rate_hz);
880+
result = parse_sample_rate_fp(optarg, endptr, &sample_rate_fp_hz);
881+
sample_rate_hz = FP_SR_HZ(sample_rate_fp_hz);
824882
sample_rate = true;
825883
break;
826884

@@ -919,7 +977,8 @@ int main(int argc, char** argv)
919977
usage();
920978
return EXIT_FAILURE;
921979
}
922-
if (((if_freq_hz > IF_MAX_HZ) || (if_freq_hz < IF_MIN_HZ)) &&
980+
if (((FP_FREQ_HZ(if_freq_fp_hz) > IF_MAX_HZ) ||
981+
(FP_FREQ_HZ(if_freq_fp_hz) < IF_MIN_HZ)) &&
923982
!force_ranges) {
924983
fprintf(stderr,
925984
"argument error: if_freq_hz should be between %s and %s.\n",
@@ -928,15 +987,17 @@ int main(int argc, char** argv)
928987
usage();
929988
return EXIT_FAILURE;
930989
}
931-
if ((if_freq_hz > IF_ABS_MAX_HZ) || (if_freq_hz < IF_ABS_MIN_HZ)) {
990+
if ((FP_FREQ_HZ(if_freq_fp_hz) > IF_ABS_MAX_HZ) ||
991+
(FP_FREQ_HZ(if_freq_fp_hz) < IF_ABS_MIN_HZ)) {
932992
fprintf(stderr,
933993
"argument error: if_freq_hz must be between %s and %s.\n",
934994
u64toa(IF_ABS_MIN_HZ, &ascii_u64_data[0]),
935995
u64toa(IF_ABS_MAX_HZ, &ascii_u64_data[1]));
936996
usage();
937997
return EXIT_FAILURE;
938998
}
939-
if ((lo_freq_hz > LO_MAX_HZ) || (lo_freq_hz < LO_MIN_HZ)) {
999+
if ((FP_FREQ_HZ(lo_freq_fp_hz) > LO_MAX_HZ) ||
1000+
(FP_FREQ_HZ(lo_freq_fp_hz) < LO_MIN_HZ)) {
9401001
fprintf(stderr,
9411002
"argument error: lo_freq_hz shall be between %s and %s.\n",
9421003
u64toa(LO_MIN_HZ, &ascii_u64_data[0]),
@@ -958,23 +1019,31 @@ int main(int argc, char** argv)
9581019
switch (image_reject_selection) {
9591020
case RF_PATH_FILTER_BYPASS:
9601021
freq_hz = if_freq_hz;
1022+
freq_fp_hz = if_freq_fp_hz;
9611023
break;
9621024
case RF_PATH_FILTER_LOW_PASS:
9631025
freq_hz = (int64_t) labs((long int) (if_freq_hz - lo_freq_hz));
1026+
// TODO check
1027+
freq_fp_hz = (if_freq_fp_hz > lo_freq_fp_hz) ?
1028+
if_freq_fp_hz - lo_freq_fp_hz :
1029+
lo_freq_fp_hz - if_freq_fp_hz;
9641030
break;
9651031
case RF_PATH_FILTER_HIGH_PASS:
9661032
freq_hz = if_freq_hz + lo_freq_hz;
1033+
freq_fp_hz = if_freq_fp_hz + lo_freq_fp_hz;
9671034
break;
9681035
default:
9691036
freq_hz = DEFAULT_FREQ_HZ;
1037+
freq_fp_hz = FREQ_FP_HZ(DEFAULT_FREQ_HZ);
9701038
break;
9711039
}
9721040
fprintf(stderr,
9731041
"explicit tuning specified for %s Hz.\n",
974-
u64toa(freq_hz, &ascii_u64_data[0]));
1042+
frequency_fp64toa(freq_fp_hz, &ascii_fp64_data[0]));
9751043

9761044
} else if (automatic_tuning) {
977-
if (((freq_hz > FREQ_MAX_HZ) || (freq_hz < FREQ_MIN_HZ)) &&
1045+
if (((FP_FREQ_HZ(freq_fp_hz) > FREQ_MAX_HZ) ||
1046+
(FP_FREQ_HZ(freq_fp_hz) < FREQ_MIN_HZ)) &&
9781047
!force_ranges) {
9791048
fprintf(stderr,
9801049
"argument error: freq_hz should be between %s and %s.\n",
@@ -983,7 +1052,7 @@ int main(int argc, char** argv)
9831052
usage();
9841053
return EXIT_FAILURE;
9851054
}
986-
if (freq_hz > FREQ_ABS_MAX_HZ) {
1055+
if (FP_FREQ_HZ(freq_fp_hz) > FREQ_ABS_MAX_HZ) {
9871056
fprintf(stderr,
9881057
"argument error: freq_hz must be between %s and %s.\n",
9891058
u64toa(FREQ_ABS_MIN_HZ, &ascii_u64_data[0]),
@@ -994,6 +1063,7 @@ int main(int argc, char** argv)
9941063
} else {
9951064
/* Use default freq */
9961065
freq_hz = DEFAULT_FREQ_HZ;
1066+
freq_fp_hz = FREQ_FP_HZ(DEFAULT_FREQ_HZ);
9971067
automatic_tuning = true;
9981068
}
9991069

@@ -1015,15 +1085,18 @@ int main(int argc, char** argv)
10151085
}
10161086

10171087
if (sample_rate) {
1018-
if (sample_rate_hz > SAMPLE_RATE_MAX_HZ && !force_ranges) {
1088+
fprintf(stderr,
1089+
"Setting sample rate to: %s Hz\n",
1090+
sample_rate_fp64toa(sample_rate_fp_hz, &ascii_fp64_data[0]));
1091+
if (FP_SR_HZ(sample_rate_fp_hz) > SAMPLE_RATE_MAX_HZ && !force_ranges) {
10191092
fprintf(stderr,
10201093
"argument error: sample_rate_hz should be less than or equal to %u Hz/%.03f MHz\n",
10211094
SAMPLE_RATE_MAX_HZ,
10221095
(float) (SAMPLE_RATE_MAX_HZ / FREQ_ONE_MHZ));
10231096
usage();
10241097
return EXIT_FAILURE;
10251098
}
1026-
if (sample_rate_hz < SAMPLE_RATE_MIN_HZ && !force_ranges) {
1099+
if (FP_SR_HZ(sample_rate_fp_hz) < SAMPLE_RATE_MIN_HZ && !force_ranges) {
10271100
fprintf(stderr,
10281101
"argument error: sample_rate_hz should be greater than or equal to %u Hz/%.03f MHz\n",
10291102
SAMPLE_RATE_MIN_HZ,
@@ -1033,6 +1106,7 @@ int main(int argc, char** argv)
10331106
}
10341107
} else {
10351108
sample_rate_hz = DEFAULT_SAMPLE_RATE_HZ;
1109+
sample_rate_fp_hz = SR_FP_HZ(DEFAULT_SAMPLE_RATE_HZ);
10361110
}
10371111

10381112
if (baseband_filter_bw) {
@@ -1100,7 +1174,7 @@ int main(int argc, char** argv)
11001174
PATH_FILE_MAX_LEN,
11011175
"HackRF_%sZ_%ukHz_IQ.wav",
11021176
date_time,
1103-
(uint32_t) (freq_hz / (1000ull)));
1177+
(uint32_t) (FP_FREQ_HZ(freq_fp_hz) / (1000ull)));
11041178
path = path_file;
11051179
fprintf(stderr, "Receive wav file: %s\n", path);
11061180
}
@@ -1116,6 +1190,7 @@ int main(int argc, char** argv)
11161190

11171191
// Change the freq and sample rate to correct the crystal clock error.
11181192
if (crystal_correct) {
1193+
// TODO this needs to be implemented for FP
11191194
sample_rate_hz =
11201195
(uint32_t) ((double) sample_rate_hz * (1000000 - crystal_correct_ppm) / 1000000 + 0.5);
11211196
freq_hz = freq_hz * (1000000 - crystal_correct_ppm) / 1000000;
@@ -1192,13 +1267,13 @@ int main(int argc, char** argv)
11921267
#endif
11931268

11941269
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);
1270+
"call hackrf_radio_set_sample_rate(%s Hz/%.03f MHz)\n",
1271+
sample_rate_fp64toa(sample_rate_fp_hz, &ascii_fp64_data[0]),
1272+
((float) FP_SR_HZ(sample_rate_fp_hz) / (float) FREQ_ONE_MHZ));
1273+
result = hackrf_radio_set_sample_rate(device, sample_rate_fp_hz);
11991274
if (result != HACKRF_SUCCESS) {
12001275
fprintf(stderr,
1201-
"hackrf_set_sample_rate() failed: %s (%d)\n",
1276+
"hackrf_radio_set_sample_rate() failed: %s (%d)\n",
12021277
hackrf_error_name(result),
12031278
result);
12041279
usage();
@@ -1246,13 +1321,13 @@ int main(int argc, char** argv)
12461321

12471322
if (automatic_tuning) {
12481323
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);
1324+
"call hackrf_radio_set_frequency(%s Hz/%.03f MHz)\n",
1325+
frequency_fp64toa(freq_fp_hz, &ascii_fp64_data[0]),
1326+
((float) FP_FREQ_HZ(freq_fp_hz) / (float) FREQ_ONE_MHZ));
1327+
result = hackrf_radio_set_frequency(device, freq_fp_hz);
12531328
if (result != HACKRF_SUCCESS) {
12541329
fprintf(stderr,
1255-
"hackrf_set_freq() failed: %s (%d)\n",
1330+
"hackrf_radio_set_frequency() failed: %s (%d)\n",
12561331
hackrf_error_name(result),
12571332
result);
12581333
usage();
@@ -1261,13 +1336,13 @@ int main(int argc, char** argv)
12611336
} else {
12621337
fprintf(stderr,
12631338
"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]),
1339+
frequency_fp64toa(if_freq_fp_hz, &ascii_fp64_data[0]),
1340+
frequency_fp64toa(lo_freq_fp_hz, &ascii_fp64_data[0]),
12661341
hackrf_filter_path_name(image_reject_selection));
1267-
result = hackrf_set_freq_explicit(
1342+
result = hackrf_radio_set_frequency_explicit(
12681343
device,
1269-
if_freq_hz,
1270-
lo_freq_hz,
1344+
if_freq_fp_hz,
1345+
lo_freq_fp_hz,
12711346
image_reject_selection);
12721347
if (result != HACKRF_SUCCESS) {
12731348
fprintf(stderr,
@@ -1532,7 +1607,8 @@ int main(int argc, char** argv)
15321607
file_pos = ftell(file);
15331608
/* Update Wav Header */
15341609
wave_file_hdr.hdr.size = file_pos - 8;
1535-
wave_file_hdr.fmt_chunk.dwSamplesPerSec = sample_rate_hz;
1610+
wave_file_hdr.fmt_chunk.dwSamplesPerSec =
1611+
FP_SR_HZ(sample_rate_fp_hz);
15361612
wave_file_hdr.fmt_chunk.dwAvgBytesPerSec =
15371613
wave_file_hdr.fmt_chunk.dwSamplesPerSec * 2;
15381614
wave_file_hdr.data_chunk.chunkSize =

0 commit comments

Comments
 (0)