From b257e18cc80d841c68bbe2aa5d21b8c3e899b892 Mon Sep 17 00:00:00 2001 From: bruceperens Date: Wed, 11 Dec 2013 23:07:39 +0000 Subject: [PATCH] Starting to write the command-line/server version of FreeDV. So far, I've just done argument parsing. git-svn-id: https://svn.code.sf.net/p/freetel/code@1334 01035d8c-6547-0410-b346-abe4f91aad63 --- freedv-server/.gitignore | 0 freedv-server/CMakeLists.txt | 100 +++++++++++++++++++++ freedv-server/source/main.cpp | 161 ++++++++++++++++++++++++++++++++++ 3 files changed, 261 insertions(+) delete mode 100644 freedv-server/.gitignore create mode 100644 freedv-server/CMakeLists.txt create mode 100644 freedv-server/source/main.cpp diff --git a/freedv-server/.gitignore b/freedv-server/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/freedv-server/CMakeLists.txt b/freedv-server/CMakeLists.txt new file mode 100644 index 00000000..6b72678c --- /dev/null +++ b/freedv-server/CMakeLists.txt @@ -0,0 +1,100 @@ +# +# FreeDV - HF Digital Voice for Radio Amateurs +# +# CMake configuration started with the version written by Richard Shaw KF5OIM +# for the original Qt FreeDV. +# Hacked to bits for command-line/server version by Bruce Perens K6BP. +# +# Please report questions, comments, problems, or patches to the freetel +# mailing list: https://lists.sourceforge.net/lists/listinfo/freetel-codec2 +# + +# Prevent in-source builds to protect automake/autoconf config. +# If an in-source build is attempted, you will still need to clean up a few +# files manually. +if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(FATAL_ERROR "In-source builds in ${CMAKE_BINARY_DIR} are not " + "allowed, please remove ./CMakeCache.txt and ./CMakeFiles/, create a " + "separate build directory and run cmake from there.") +endif("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + +cmake_minimum_required(VERSION 2.8) +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) +project(freedv-server) + +# Parameters are stored as .txt files in the parameters/ subdirectory. +# They use semicolon to separate arguments, because this is what cmake uses +# in its list type. Thus, parameters/version.txt looks like this: +# +# 0;1;2 +# +# Those are easy to separate at each semicolon into the major, minor, +# and patch version. +# +# You can override parameters on the command line, using +# -DParam.name=value +# +macro(load_parameters) + foreach(name ${ARGN}) + set(filename "${CMAKE_SOURCE_DIR}/parameters/${name}.txt") + if("${Param.${name}}" STREQUAL "" AND EXISTS ${filename}) + file(STRINGS ${filename} string) + set("Param.${name}" ${string}) + endif("${Param.${name}}" STREQUAL "" AND EXISTS ${filename}) + endforeach(name) + unset(filename) +endmacro(load_parameters) + +# +# Parse FreeDV version, code-name from parameter. +# +load_parameters(version codename build-type) +list(GET Param.version 0 Version.major) +list(GET Param.version 1 Version.minor) +list(GET Param.version 2 Version.patch) +unset(list) + +# +# Parse platform information +# +set(Platform.name ${CMAKE_SYSTEM_NAME}) +if(Platform.name STREQUAL Linux) + execute_process( + COMMAND lsb_release -s -i + OUTPUT_VARIABLE Platform.distribution + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process( + COMMAND lsb_release -s -r + OUTPUT_VARIABLE Platform.release + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif(Platform.name STREQUAL Linux) + +message(STATUS "${Param.build-type} ${Version.major}.${Version.minor}.${Version.patch}, " + "code name \"${Param.codename}\", " + "on ${Platform.name} ${Platform.distribution} ${Platform.release}.") + +# +# Set cmake internal variables from parameters. +# +load_parameters(cxx-flags c-flags) +set(CMAKE_CXX_FLAGS, ${Param.cxx-flags}) +set(CMAKE_C_FLAGS, ${Param.c-flags}) + +set(Compile.sources + source/main.cpp +) + +add_executable(freedv-server ${Compile.sources}) + +find_path(Codec2.include codec2.h PATH_SUFFIXES codec2) +find_library(Codec2.lib NAMES codec2) +if( Codec2.lib AND Codec2.include ) + message(STATUS "Getting Codec2 from ${Codec2.include} and ${Codec2.lib}") + include_directories(${Codec2.include}) + target_link_libraries(freedv-server ${Codec2.lib}) +else( Codec2.lib AND Codec2.include ) + message(FATAL_ERROR "Can't find Codec2 library.") +endif( Codec2.lib AND Codec2.include ) + +install(TARGETS freedv-server RUNTIME DESTINATION bin) diff --git a/freedv-server/source/main.cpp b/freedv-server/source/main.cpp new file mode 100644 index 00000000..042cc066 --- /dev/null +++ b/freedv-server/source/main.cpp @@ -0,0 +1,161 @@ +/* + * For the sake of correctness and optimization, I have written whatever I can to be without + * side-effects, a style inherited from functional programming. Thus, the excessive use of + * "const". - Bruce + */ +#include +#include +#include +#include +#include +#include + +using namespace std; + +static void drivers() +{ + cout << "To be implemented." << endl; +} + +static void help(const char * name) +{ + static const char message[] = + " [options]\n" + "\n\tWhere options are these flags:\n\n" + "\t\t--drivers or -d\t\tPrint a list of the available device drivers.\n" + "\t\t--help or -h\t\tPrint this message.\n" + "\t\t--interface or -i\tSelect the user-interface (graphical or otherwise).\n" + "\t\t--keying or -k\t\tSelect the transmitter keying interface.\n" + "\t\t--loudspeaker or -l\tSelect the operator audio output interface.\n" + "\t\t--microphone or -m\tSelect the operator audio input interface.\n" + "\t\t--mode or -n\t\tSelect the codec mode and modulation.\n" + "\t\t--ptt or -p\t\tSelect the push-to-talk input interface.\n" + "\t\t--receiver or -r\tSelect the interface for audio input from the receiver.\n" + "\t\t--text or -x\t\tSelect the interface for text to be transmitted.\n" + "\t\t--transmitter or -t\tSelect the interface for audio output to the transmitter.\n" + "\n\tLong flags with parameters are in the form of --=\n" + "\tShort flags with parameters are in the form of - \n" + "\n\tFor example, both of these flags have the same effect:\n" + "\t\t-m 1600\n" + "\t\t--mode=1600\n" + "\n\tMode may be one of:\n" + "\t\t--mode=1600\t\tNormal 1600 bit-per-second in 1.275 kHz RF bandwidth.\n" + "\t\t--mode=1600-wide\t1600 bit-per-second in 2.125 kHz, wider guard-bands for improved\n" + "\t\t\t\t\tDX performance.\n" + "\n\tFlags used to select devices must have a \":\" argument\n" + "\twhere is the name of a device driver for the selected input/output device,\n" + "\tand is the name or address of the selected device.\n" + "\n\tExample:\n" + "\t\t --loudspeaker=alsa:default\n" + ; + cerr << "\nUsage: " << name << message << endl; +} + +struct parameters { + const char * * interface; + const char * * keying; + const char * * loudspeaker; + const char * * microphone; + const char * mode; + const char * * ptt; + const char * * receiver; + const char * * text; + const char * * transmitter; +}; + +static int run(struct parameters * p) +{ + return 0; +} + +int +main(int argc, char * * argv) +{ + int command; + struct parameters p = { 0,0,0,0,0,0,0,0,0 }; + + static const struct option options[] = { + { "drivers", no_argument, 0, 'd' }, + { "help", no_argument, 0, 'h' }, + { "interface", required_argument, 0, 'i' }, + { "keying", required_argument, 0, 'k' }, + { "loudspeaker", required_argument, 0, 'l' }, + { "microphone", required_argument, 0, 'm' }, + { "mode", required_argument, 0, 'n' }, + { "ptt", required_argument, 0, 'p' }, + { "receiver", required_argument, 0, 'r' }, + { "text", required_argument, 0, 'x' }, + { "transmitter", required_argument, 0, 't' }, + { 0, 0, 0, 0 } + }; + + if ( argc > 1 ) { + const char * * vector(new const char *[2]); + + while ((command = getopt_long(argc, argv, "dhi:k:l:m:n:p:r:t:x:", options, NULL)) != -1) { + switch (command) { + case 'i': + case 'k': + case 'l': + case 'm': + case 'p': + case 'r': + case 't': + case 'x': + char * const colon(index(optarg, ':')); + + if ( colon == 0 || *colon == 0 ) { + cerr << argv[optind - 1] << ": Missing colon. Argument must be of the form \":\"" << endl; + exit(1); + } + } + + switch (command) { + case 'd': + drivers(); + exit(0); + break; + default: + case 'h': + help(argv[0]); + exit(1); + break; + case 'i': + p.interface = vector; + break; + case 'k': + p.keying = vector; + break; + case 'l': + p.loudspeaker = vector; + break; + case 'm': + p.microphone = vector; + break; + case 'n': + p.mode = optarg; + break; + case 'p': + p.ptt = vector; + break; + case 'r': + p.receiver = vector; + break; + case 't': + p.transmitter = vector; + break; + case 'x': + p.text = vector; + break; + case 0: + break; + } + } + } + else { // argc <= 1 + help(argv[0]); + exit(1); + } + run(&p); + return 0; +} -- 2.25.1