From 7a33c7221b9cebf0786b77fc324e9f2995ca729d Mon Sep 17 00:00:00 2001 From: Alexander Chemeris Date: Sun, 26 Mar 2017 21:49:46 -0700 Subject: osmo-trx-gen: generates waveform files aka IQ binary files in a number of formats. Generated files can be used as an input to osmo-trx-dec or load them into signal generators. Change-Id: I555d99a632755b5bfcbaf3501a501613c2859d4e --- Transceiver52M/osmo-trx-gen.cpp | 334 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 Transceiver52M/osmo-trx-gen.cpp (limited to 'Transceiver52M/osmo-trx-gen.cpp') diff --git a/Transceiver52M/osmo-trx-gen.cpp b/Transceiver52M/osmo-trx-gen.cpp new file mode 100644 index 0000000..0eb82ef --- /dev/null +++ b/Transceiver52M/osmo-trx-gen.cpp @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2017 Alexander Chemeris + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include // for byte order manipulation + +#include "Logger.h" +#include "sigProcLib.h" +#include "GSMCommon.h" +#include "BitVector.h" +#include "Configuration.h" + +extern "C" { +#include "convolve.h" +#include "convert.h" +} + +#define DEFAULT_SPS 4 +#define DEFAULT_SEARCH_WINDOW 30 + +// Tail + data + stealing + midamble + guard (without the last 0.25) +#define BURST_LEN_FULL 156 +// Tail + data + stealing + midamble +#define BURST_LEN_ACTIVE 148 +// Tail + data + stealing + midamble - 2*0.5 +#define BURST_LEN_USEFUL 147 + +// Size of a sample in bytes as stores in a file +#define SAMPLE_SIZE_BYTES (2 * sizeof(float)) +// Burst length in bytes as stored in a file +#define BURST_LEN_BYTES (BURST_LEN_FULL * SAMPLE_SIZE_BYTES) + +ConfigurationTable gConfig; + +enum FileType { + FLOAT_NORM_LE, ///< Float -1..+1 Little Endian + FLOAT16_LE, ///< Float -32767..+32767 Little Endian + SIGNED16_LE, ///< Integer -32767..+32767 Little Endian + SIGNED16_BE, ///< Integer -32767..+32767 Big Endian (Keysight waveform format) +}; + +struct trx_config { + std::string log_level; + unsigned sps; + unsigned tsc; + double full_scale; + bool edge; + CorrType type; + std::string filename; + FileType file_type; +}; + +std::ostream& operator<<(std::ostream& os, FileType ftype) +{ + switch(ftype) + { + case FLOAT_NORM_LE: + os << "float"; + break; + case FLOAT16_LE: + os << "float16"; + break; + case SIGNED16_LE: + os << "signed16"; + break; + case SIGNED16_BE: + os << "signed16be"; + break; + default: + assert(!"unknown file type"); + } + return os; +} + + +void writeBurstFloatNorm(std::ofstream& os, const signalVector& v) +{ + os.write((char*)v.begin(), v.size() * 2 * sizeof(float)); +} + +void writeBurstFloat16LE(std::ofstream& os, const signalVector& v) +{ + const complex *c = v.begin(); + for (size_t i=0; ireal()*SHRT_MAX; + iq[1] = c->imag()*SHRT_MAX; + os.write((char*)&iq, 2*sizeof(float)); + } +} + +void writeBurstSigned16LE(std::ofstream& os, const signalVector& v) +{ + const complex *c = v.begin(); + for (size_t i=0; ireal()*SHRT_MAX; + iq[1] = c->imag()*SHRT_MAX; + iq[0] = htole16(iq[0]); + iq[1] = htole16(iq[1]); + os.write((char*)&iq, 2*sizeof(int16_t)); + } +} + +void writeBurstSigned16BE(std::ofstream& os, const signalVector& v) +{ + const complex *c = v.begin(); + for (size_t i=0; ireal()*SHRT_MAX; + iq[1] = c->imag()*SHRT_MAX; + iq[0] = htobe16(iq[0]); + iq[1] = htobe16(iq[1]); + os.write((char*)&iq, 2*sizeof(int16_t)); + } +} + +void writeBurst(std::ofstream& os, const signalVector& v, FileType ftype) +{ + switch(ftype) + { + case FLOAT_NORM_LE: + writeBurstFloatNorm(os, v); + break; + case FLOAT16_LE: + writeBurstFloat16LE(os, v); + break; + case SIGNED16_LE: + writeBurstSigned16LE(os, v); + break; + case SIGNED16_BE: + writeBurstSigned16BE(os, v); + break; + default: + assert(!"unknown file type"); + } +} + +// Setup configuration values +static void print_config(struct trx_config *config) +{ + std::ostringstream ost(""); + ost << "Config Settings" << std::endl; + ost << " Destination file name........ " << config->filename << std::endl; + ost << " Destination file type........ " << config->file_type << std::endl; + ost << " Log Level.................... " << config->log_level << std::endl; + ost << " Tx Samples-per-Symbol........ " << config->sps << std::endl; + ost << " EDGE support................. " << (config->edge ? "Enabled" : "Disabled") << std::endl; + ost << " Burst type................... " << config->type << std::endl; + ost << " Burst TSC.................... " << config->tsc << std::endl; + ost << " Signal full scale............ " << config->full_scale << std::endl; + std::cout << ost << std::endl; +} + +static void print_help() +{ + fprintf(stdout, + "This utility generates waveform files aka IQ binary files in a number of formats" + "to use them as input to osmo-trx-dec or load them into signal generators.\n" + "\n" + "Options:\n" + " -h This text\n" + " -l LEVEL Logging level (%s)\n" + " -e Enable EDGE receiver\n" + " -s SPS Samples-per-symbol (1 or 4, default: %d)\n" + " -t TSC Burst training sequence (0 to 7, default: 0)\n" + " -f FILE File to write generated bursts to\n" + " -F FILETYPE Format of the file - float, float16, signed16, signed16be (default: f16)\n" + " Note: Keysight waveform format is signed16be. osmo-trx-dec accepts float16.\n", + "EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG", + DEFAULT_SPS); +} + +FileType option_to_file_type(const std::string &optarg) +{ + if (optarg == "float") { + return FLOAT_NORM_LE; + } else if (optarg == "float16") { + return FLOAT16_LE; + } else if (optarg == "signed16") { + return SIGNED16_LE; + } else if (optarg == "signed16be") { + return SIGNED16_BE; + } else { + return (FileType)-1; + } +} + +static bool handle_options(int argc, char **argv, struct trx_config *config) +{ + int option; + + config->log_level = "NOTICE"; + config->sps = DEFAULT_SPS; + config->tsc = 0; + config->full_scale = SHRT_MAX; + config->edge = false; + config->type = TSC; + config->file_type = FLOAT16_LE; + + while ((option = getopt(argc, argv, "ls:et:f:F:h")) != -1) { + switch (option) { + case 'l': + config->log_level = optarg; + break; + case 's': + config->sps = atoi(optarg); + break; + case 'e': + config->edge = true; + break; + case 't': + config->tsc = atoi(optarg); + break; + case 'f': + config->filename = optarg; + break; + case 'F': + config->file_type = option_to_file_type(optarg); + break; + case 'h': + default: + print_help(); + exit(0); + } + } + + if ((config->sps != 1) && (config->sps != 4)) { + printf("ERROR: Unsupported samples-per-symbol %i\n\n", config->sps); + return false; + } + + if (config->edge && (config->sps != 4)) { + printf("ERROR: EDGE only supported at 4 samples per symbol\n\n"); + return false; + } + + if (config->tsc > 7) { + printf("ERROR: Invalid training sequence %i\n\n", config->tsc); + return false; + } + + if (config->filename.length() == 0) { + printf("ERROR: No output file name specified\n\n"); + return false; + } + + if (config->file_type < 0) { + printf("ERROR: Wrong output file format\n\n"); + } + + return true; +} + +int main(int argc, char *argv[]) +{ + struct trx_config config; + +#ifdef HAVE_SSE3 + printf("Info: SSE3 support compiled in"); + if (__builtin_cpu_supports("sse3")) + printf(" and supported by CPU\n"); + else + printf(", but not supported by CPU\n"); +#endif + +#ifdef HAVE_SSE4_1 + printf("Info: SSE4.1 support compiled in"); + if (__builtin_cpu_supports("sse4.1")) + printf(" and supported by CPU\n"); + else + printf(", but not supported by CPU\n"); +#endif + + convolve_init(); + convert_init(); + + // Process command line options and print config to screen + if (!handle_options(argc, argv, &config)) { + print_help(); + exit(0); + } + print_config(&config); + + gLogInit("transceiver", config.log_level.c_str(), LOG_LOCAL7); + + if (!sigProcLibSetup()) { + LOG(ALERT) << "Failed to initialize signal processing library"; + return -1; + } + + signalVector burst(2*BURST_LEN_FULL); + GSM::Time gsmTime; + PRBS9 prbs; + + // Configure output stream + std::cout << std::fixed; + std::cout << std::setprecision(2); + + std::ofstream file (config.filename.c_str(), std::ifstream::binary); + + for (int i=0; i<511; i++) { + signalVector *signal = genRandNormalBurst(config.tsc, config.sps, gsmTime.TN(), prbs); + writeBurst(file, *signal, config.file_type); + gsmTime.incTN(); + } + + file.close(); + + std::cout << "Done!" << std::endl; + + return 0; +} -- cgit v1.2.3