Skip to content

Commit fc93b26

Browse files
committed
hackrf_transfer: add fixed-point support for frequency and sample rate
1 parent ddc6c49 commit fc93b26

1 file changed

Lines changed: 115 additions & 51 deletions

File tree

host/hackrf-tools/src/hackrf_transfer.c

Lines changed: 115 additions & 51 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,13 @@ struct timeval time_start;
351402
struct timeval t_start;
352403

353404
bool automatic_tuning = false;
354-
int64_t freq_hz;
405+
fp_40_24_t freq_fp_hz;
355406

356407
bool if_freq = false;
357-
int64_t if_freq_hz;
408+
fp_40_24_t if_freq_fp_hz;
358409

359410
bool lo_freq = false;
360-
int64_t lo_freq_hz = DEFAULT_LO_HZ;
411+
fp_40_24_t lo_freq_fp_hz = FREQ_FP_HZ(DEFAULT_LO_HZ);
361412

362413
bool image_reject = false;
363414
uint32_t image_reject_selection;
@@ -369,7 +420,7 @@ bool antenna = false;
369420
uint32_t antenna_enable;
370421

371422
bool sample_rate = false;
372-
uint32_t sample_rate_hz;
423+
fp_28_36_t sample_rate_fp_hz;
373424

374425
bool force_ranges = false;
375426

@@ -778,17 +829,17 @@ int main(int argc, char** argv)
778829
break;
779830

780831
case 'f':
781-
result = parse_frequency_i64(optarg, endptr, &freq_hz);
832+
result = parse_frequency_fp(optarg, endptr, &freq_fp_hz);
782833
automatic_tuning = true;
783834
break;
784835

785836
case 'i':
786-
result = parse_frequency_i64(optarg, endptr, &if_freq_hz);
837+
result = parse_frequency_fp(optarg, endptr, &if_freq_fp_hz);
787838
if_freq = true;
788839
break;
789840

790841
case 'o':
791-
result = parse_frequency_i64(optarg, endptr, &lo_freq_hz);
842+
result = parse_frequency_fp(optarg, endptr, &lo_freq_fp_hz);
792843
lo_freq = true;
793844
break;
794845

@@ -820,7 +871,7 @@ int main(int argc, char** argv)
820871
break;
821872

822873
case 's':
823-
result = parse_frequency_u32(optarg, endptr, &sample_rate_hz);
874+
result = parse_sample_rate_fp(optarg, endptr, &sample_rate_fp_hz);
824875
sample_rate = true;
825876
break;
826877

@@ -919,7 +970,8 @@ int main(int argc, char** argv)
919970
usage();
920971
return EXIT_FAILURE;
921972
}
922-
if (((if_freq_hz > IF_MAX_HZ) || (if_freq_hz < IF_MIN_HZ)) &&
973+
if (((FP_FREQ_HZ(if_freq_fp_hz) > IF_MAX_HZ) ||
974+
(FP_FREQ_HZ(if_freq_fp_hz) < IF_MIN_HZ)) &&
923975
!force_ranges) {
924976
fprintf(stderr,
925977
"argument error: if_freq_hz should be between %s and %s.\n",
@@ -928,15 +980,17 @@ int main(int argc, char** argv)
928980
usage();
929981
return EXIT_FAILURE;
930982
}
931-
if ((if_freq_hz > IF_ABS_MAX_HZ) || (if_freq_hz < IF_ABS_MIN_HZ)) {
983+
if ((FP_FREQ_HZ(if_freq_fp_hz) > IF_ABS_MAX_HZ) ||
984+
(FP_FREQ_HZ(if_freq_fp_hz) < IF_ABS_MIN_HZ)) {
932985
fprintf(stderr,
933986
"argument error: if_freq_hz must be between %s and %s.\n",
934987
u64toa(IF_ABS_MIN_HZ, &ascii_u64_data[0]),
935988
u64toa(IF_ABS_MAX_HZ, &ascii_u64_data[1]));
936989
usage();
937990
return EXIT_FAILURE;
938991
}
939-
if ((lo_freq_hz > LO_MAX_HZ) || (lo_freq_hz < LO_MIN_HZ)) {
992+
if ((FP_FREQ_HZ(lo_freq_fp_hz) > LO_MAX_HZ) ||
993+
(FP_FREQ_HZ(lo_freq_fp_hz) < LO_MIN_HZ)) {
940994
fprintf(stderr,
941995
"argument error: lo_freq_hz shall be between %s and %s.\n",
942996
u64toa(LO_MIN_HZ, &ascii_u64_data[0]),
@@ -957,24 +1011,27 @@ int main(int argc, char** argv)
9571011
}
9581012
switch (image_reject_selection) {
9591013
case RF_PATH_FILTER_BYPASS:
960-
freq_hz = if_freq_hz;
1014+
freq_fp_hz = if_freq_fp_hz;
9611015
break;
9621016
case RF_PATH_FILTER_LOW_PASS:
963-
freq_hz = (int64_t) labs((long int) (if_freq_hz - lo_freq_hz));
1017+
freq_fp_hz = (if_freq_fp_hz > lo_freq_fp_hz) ?
1018+
if_freq_fp_hz - lo_freq_fp_hz :
1019+
lo_freq_fp_hz - if_freq_fp_hz;
9641020
break;
9651021
case RF_PATH_FILTER_HIGH_PASS:
966-
freq_hz = if_freq_hz + lo_freq_hz;
1022+
freq_fp_hz = if_freq_fp_hz + lo_freq_fp_hz;
9671023
break;
9681024
default:
969-
freq_hz = DEFAULT_FREQ_HZ;
1025+
freq_fp_hz = FREQ_FP_HZ(DEFAULT_FREQ_HZ);
9701026
break;
9711027
}
9721028
fprintf(stderr,
9731029
"explicit tuning specified for %s Hz.\n",
974-
u64toa(freq_hz, &ascii_u64_data[0]));
1030+
frequency_fp64toa(freq_fp_hz, &ascii_fp64_data[0]));
9751031

9761032
} else if (automatic_tuning) {
977-
if (((freq_hz > FREQ_MAX_HZ) || (freq_hz < FREQ_MIN_HZ)) &&
1033+
if (((FP_FREQ_HZ(freq_fp_hz) > FREQ_MAX_HZ) ||
1034+
(FP_FREQ_HZ(freq_fp_hz) < FREQ_MIN_HZ)) &&
9781035
!force_ranges) {
9791036
fprintf(stderr,
9801037
"argument error: freq_hz should be between %s and %s.\n",
@@ -983,7 +1040,7 @@ int main(int argc, char** argv)
9831040
usage();
9841041
return EXIT_FAILURE;
9851042
}
986-
if (freq_hz > FREQ_ABS_MAX_HZ) {
1043+
if (FP_FREQ_HZ(freq_fp_hz) > FREQ_ABS_MAX_HZ) {
9871044
fprintf(stderr,
9881045
"argument error: freq_hz must be between %s and %s.\n",
9891046
u64toa(FREQ_ABS_MIN_HZ, &ascii_u64_data[0]),
@@ -993,7 +1050,7 @@ int main(int argc, char** argv)
9931050
}
9941051
} else {
9951052
/* Use default freq */
996-
freq_hz = DEFAULT_FREQ_HZ;
1053+
freq_fp_hz = FREQ_FP_HZ(DEFAULT_FREQ_HZ);
9971054
automatic_tuning = true;
9981055
}
9991056

@@ -1015,15 +1072,18 @@ int main(int argc, char** argv)
10151072
}
10161073

10171074
if (sample_rate) {
1018-
if (sample_rate_hz > SAMPLE_RATE_MAX_HZ && !force_ranges) {
1075+
fprintf(stderr,
1076+
"Setting sample rate to: %s Hz\n",
1077+
sample_rate_fp64toa(sample_rate_fp_hz, &ascii_fp64_data[0]));
1078+
if (FP_SR_HZ(sample_rate_fp_hz) > SAMPLE_RATE_MAX_HZ && !force_ranges) {
10191079
fprintf(stderr,
10201080
"argument error: sample_rate_hz should be less than or equal to %u Hz/%.03f MHz\n",
10211081
SAMPLE_RATE_MAX_HZ,
10221082
(float) (SAMPLE_RATE_MAX_HZ / FREQ_ONE_MHZ));
10231083
usage();
10241084
return EXIT_FAILURE;
10251085
}
1026-
if (sample_rate_hz < SAMPLE_RATE_MIN_HZ && !force_ranges) {
1086+
if (FP_SR_HZ(sample_rate_fp_hz) < SAMPLE_RATE_MIN_HZ && !force_ranges) {
10271087
fprintf(stderr,
10281088
"argument error: sample_rate_hz should be greater than or equal to %u Hz/%.03f MHz\n",
10291089
SAMPLE_RATE_MIN_HZ,
@@ -1032,7 +1092,7 @@ int main(int argc, char** argv)
10321092
return EXIT_FAILURE;
10331093
}
10341094
} else {
1035-
sample_rate_hz = DEFAULT_SAMPLE_RATE_HZ;
1095+
sample_rate_fp_hz = SR_FP_HZ(DEFAULT_SAMPLE_RATE_HZ);
10361096
}
10371097

10381098
if (baseband_filter_bw) {
@@ -1100,7 +1160,7 @@ int main(int argc, char** argv)
11001160
PATH_FILE_MAX_LEN,
11011161
"HackRF_%sZ_%ukHz_IQ.wav",
11021162
date_time,
1103-
(uint32_t) (freq_hz / (1000ull)));
1163+
(uint32_t) (FP_FREQ_HZ(freq_fp_hz) / (1000ull)));
11041164
path = path_file;
11051165
fprintf(stderr, "Receive wav file: %s\n", path);
11061166
}
@@ -1116,9 +1176,12 @@ int main(int argc, char** argv)
11161176

11171177
// Change the freq and sample rate to correct the crystal clock error.
11181178
if (crystal_correct) {
1119-
sample_rate_hz =
1120-
(uint32_t) ((double) sample_rate_hz * (1000000 - crystal_correct_ppm) / 1000000 + 0.5);
1121-
freq_hz = freq_hz * (1000000 - crystal_correct_ppm) / 1000000;
1179+
sample_rate_fp_hz =
1180+
(fp_28_36_t) ((__uint128_t) sample_rate_fp_hz * (1000000 - crystal_correct_ppm)) /
1181+
1000000;
1182+
freq_fp_hz =
1183+
(fp_40_24_t) ((__uint128_t) freq_fp_hz * (1000000 - crystal_correct_ppm)) /
1184+
1000000;
11221185
}
11231186

11241187
result = hackrf_init();
@@ -1192,13 +1255,13 @@ int main(int argc, char** argv)
11921255
#endif
11931256

11941257
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);
1258+
"call hackrf_radio_set_sample_rate(%s Hz/%.03f MHz)\n",
1259+
sample_rate_fp64toa(sample_rate_fp_hz, &ascii_fp64_data[0]),
1260+
((float) FP_SR_HZ(sample_rate_fp_hz) / (float) FREQ_ONE_MHZ));
1261+
result = hackrf_radio_set_sample_rate(device, sample_rate_fp_hz);
11991262
if (result != HACKRF_SUCCESS) {
12001263
fprintf(stderr,
1201-
"hackrf_set_sample_rate() failed: %s (%d)\n",
1264+
"hackrf_radio_set_sample_rate() failed: %s (%d)\n",
12021265
hackrf_error_name(result),
12031266
result);
12041267
usage();
@@ -1246,13 +1309,13 @@ int main(int argc, char** argv)
12461309

12471310
if (automatic_tuning) {
12481311
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);
1312+
"call hackrf_radio_set_frequency(%s Hz/%.03f MHz)\n",
1313+
frequency_fp64toa(freq_fp_hz, &ascii_fp64_data[0]),
1314+
((float) FP_FREQ_HZ(freq_fp_hz) / (float) FREQ_ONE_MHZ));
1315+
result = hackrf_radio_set_frequency(device, freq_fp_hz);
12531316
if (result != HACKRF_SUCCESS) {
12541317
fprintf(stderr,
1255-
"hackrf_set_freq() failed: %s (%d)\n",
1318+
"hackrf_radio_set_frequency() failed: %s (%d)\n",
12561319
hackrf_error_name(result),
12571320
result);
12581321
usage();
@@ -1261,13 +1324,13 @@ int main(int argc, char** argv)
12611324
} else {
12621325
fprintf(stderr,
12631326
"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]),
1327+
frequency_fp64toa(if_freq_fp_hz, &ascii_fp64_data[0]),
1328+
frequency_fp64toa(lo_freq_fp_hz, &ascii_fp64_data[0]),
12661329
hackrf_filter_path_name(image_reject_selection));
1267-
result = hackrf_set_freq_explicit(
1330+
result = hackrf_radio_set_frequency_explicit(
12681331
device,
1269-
if_freq_hz,
1270-
lo_freq_hz,
1332+
if_freq_fp_hz,
1333+
lo_freq_fp_hz,
12711334
image_reject_selection);
12721335
if (result != HACKRF_SUCCESS) {
12731336
fprintf(stderr,
@@ -1532,7 +1595,8 @@ int main(int argc, char** argv)
15321595
file_pos = ftell(file);
15331596
/* Update Wav Header */
15341597
wave_file_hdr.hdr.size = file_pos - 8;
1535-
wave_file_hdr.fmt_chunk.dwSamplesPerSec = sample_rate_hz;
1598+
wave_file_hdr.fmt_chunk.dwSamplesPerSec =
1599+
FP_SR_HZ(sample_rate_fp_hz);
15361600
wave_file_hdr.fmt_chunk.dwAvgBytesPerSec =
15371601
wave_file_hdr.fmt_chunk.dwSamplesPerSec * 2;
15381602
wave_file_hdr.data_chunk.chunkSize =

0 commit comments

Comments
 (0)