Compare commits
26 Commits
minimodem-
...
master
Author | SHA1 | Date |
---|---|---|
Sebastien Van Cauwenberghe | 9a1e8769ab | |
Kamal Mostafa | d4ce82136d | |
Kamal Mostafa | 17e17b784e | |
Kamal Mostafa | fc03264643 | |
Kamal Mostafa | ea3f837c90 | |
Kamal Mostafa | 78cff1778b | |
Kamal Mostafa | c2e4d9e1c4 | |
Chris Osborn | 513a11d454 | |
Kamal Mostafa | 84b2406b97 | |
Kamal Mostafa | ad83ef5df3 | |
Colin Ian King | 96a60f51b0 | |
Colin Ian King | 2d3bd487ca | |
Colin Ian King | 7397c3cd9b | |
Colin Ian King | d6a616fff8 | |
Colin Ian King | 632e92f1ae | |
Kamal Mostafa | 93b35cbd9d | |
Kamal Mostafa | 3a8d490074 | |
Kamal Mostafa | bc794806db | |
Kamal Mostafa | 37bf388038 | |
Kamal Mostafa | f801ae3f28 | |
Kamal Mostafa | 842c1923e2 | |
Kamal Mostafa | 6e22843115 | |
Kamal Mostafa | 4b3301a7ef | |
Rodrigo Menezes | f48257ac59 | |
Kevin Zheng | a23c5c73be | |
Kevin Zheng | 40c1f4c35c |
2
COPYING
2
COPYING
|
@ -1,5 +1,5 @@
|
||||||
minimodem - software audio Bell-type or RTTY FSK modem
|
minimodem - software audio Bell-type or RTTY FSK modem
|
||||||
Copyright (C) 2011-2014 Kamal Mostafa <kamal@whence.com>
|
Copyright (C) 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|
6
README
6
README
|
@ -1,11 +1,11 @@
|
||||||
minimodem - general-purpose software audio FSK modem
|
minimodem - general-purpose software audio FSK modem
|
||||||
Copyright (C) 2011-2014 Kamal Mostafa <kamal@whence.com>
|
Copyright (C) 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
|
|
||||||
Minimodem is a command-line program which decodes (or generates) audio
|
Minimodem is a command-line program which decodes (or generates) audio
|
||||||
modem tones at any specified baud rate, using various framing protocols.
|
modem tones at any specified baud rate, using various framing protocols.
|
||||||
It acts a general-purpose software FSK modem, and includes support for
|
It acts a general-purpose software FSK modem, and includes support for
|
||||||
various standard FSK protocols such as Bell103, Bell202, RTTY, NOAA SAME,
|
various standard FSK protocols such as Bell103, Bell202, RTTY, TTY/TDD,
|
||||||
and Caller-ID.
|
NOAA SAME, and Caller-ID.
|
||||||
|
|
||||||
Minimodem can play and capture audio modem tones in real-time via the
|
Minimodem can play and capture audio modem tones in real-time via the
|
||||||
system audio device, or in batched mode via audio files.
|
system audio device, or in batched mode via audio files.
|
||||||
|
|
152
configure.ac
152
configure.ac
|
@ -1,121 +1,79 @@
|
||||||
dnl
|
|
||||||
dnl configure.ac Generated by project-setup
|
|
||||||
dnl
|
|
||||||
|
|
||||||
AC_DEFUN([PKG_NAME], [minimodem])
|
|
||||||
AC_DEFUN([PKG_VERSION], [0.22.1])
|
|
||||||
AC_DEFUN([PKG_AUTHOR], [Kamal Mostafa <kamal@whence.com>])
|
|
||||||
AC_DEFUN([PKG_BUGS_TO], [kamal@whence.com])
|
|
||||||
|
|
||||||
|
|
||||||
AC_PREREQ([2.64])
|
AC_PREREQ([2.64])
|
||||||
|
AC_INIT([minimodem], [0.24], [kamal@whence.com])
|
||||||
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
AC_CONFIG_SRCDIR([src/Makefile.in])
|
||||||
|
AM_INIT_AUTOMAKE
|
||||||
|
|
||||||
AC_INIT(PKG_NAME, PKG_VERSION, PKG_BUGS_TO)
|
VERSION=AC_PACKAGE_VERSION
|
||||||
|
|
||||||
dnl Release versioning info
|
|
||||||
VERSION=PKG_VERSION
|
|
||||||
AC_SUBST(VERSION)
|
AC_SUBST(VERSION)
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE
|
# Program Checks
|
||||||
AC_CONFIG_SRCDIR([src/Makefile.in])
|
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
|
||||||
|
|
||||||
# AC_CONFIG_MACRO_DIR([m4])
|
|
||||||
|
|
||||||
# Checks for programs.
|
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
# AC_PROG_RANLIB
|
|
||||||
|
|
||||||
|
# Library Checks
|
||||||
|
AC_SEARCH_LIBS([lroundf], [m])
|
||||||
|
|
||||||
# Configure dependency libs
|
deps_packages="fftw3f"
|
||||||
|
|
||||||
AC_CHECK_LIB([m],[lroundf])
|
|
||||||
|
|
||||||
# fftw3f
|
|
||||||
deps_packages+=" fftw3f"
|
|
||||||
|
|
||||||
# ALSA
|
# ALSA
|
||||||
AC_ARG_WITH([alsa],
|
AC_ARG_WITH([alsa], [AS_HELP_STRING([--without-alsa],
|
||||||
AS_HELP_STRING([--without-alsa], [build without ALSA support]))
|
[build without ALSA support])])
|
||||||
AS_IF([test "x$with_alsa" == "xno"],
|
AS_IF([test "x$with_alsa" == "xno"], [
|
||||||
# then
|
use_alsa=0
|
||||||
use_alsa=0,
|
], [
|
||||||
# else
|
use_alsa=1
|
||||||
use_alsa=1
|
deps_packages="$deps_packages alsa"
|
||||||
deps_packages+=" alsa")
|
])
|
||||||
AC_DEFINE_UNQUOTED(USE_ALSA, $use_alsa,
|
AC_DEFINE_UNQUOTED([USE_ALSA], [$use_alsa],
|
||||||
[Define to 1 to enable ALSA support])
|
[Define to 1 to enable ALSA support])
|
||||||
|
|
||||||
# pulseaudio
|
# pulseaudio
|
||||||
AC_ARG_WITH([pulseaudio],
|
AC_ARG_WITH([pulseaudio], AS_HELP_STRING([--without-pulseaudio],
|
||||||
AS_HELP_STRING([--without-pulseaudio], [build without pulseaudio support]))
|
[build without pulseaudio support]))
|
||||||
AS_IF([test "x$with_pulseaudio" == "xno"],
|
AS_IF([test "x$with_pulseaudio" == "xno"], [
|
||||||
# then
|
use_pulseaudio=0
|
||||||
use_pulseaudio=0,
|
], [
|
||||||
# else
|
use_pulseaudio=1
|
||||||
use_pulseaudio=1
|
deps_packages="$deps_packages libpulse-simple"
|
||||||
deps_packages+=" libpulse-simple")
|
])
|
||||||
AC_DEFINE_UNQUOTED(USE_PULSEAUDIO, $use_pulseaudio,
|
AC_DEFINE_UNQUOTED([USE_PULSEAUDIO], [$use_pulseaudio],
|
||||||
[Define to 1 to enable pulseaudio support])
|
[Define to 1 to enable pulseaudio support])
|
||||||
|
|
||||||
# sndfile
|
# sndfile
|
||||||
AC_ARG_WITH([sndfile],
|
AC_ARG_WITH([sndfile], AS_HELP_STRING([--without-sndfile],
|
||||||
AS_HELP_STRING([--without-sndfile], [build without sndfile support]))
|
[build without sndfile support]))
|
||||||
AS_IF([test "x$with_sndfile" == "xno"],
|
AS_IF([test "x$with_sndfile" == "xno"], [
|
||||||
# then
|
use_sndfile=0
|
||||||
use_sndfile=0,
|
], [
|
||||||
# else
|
use_sndfile=1
|
||||||
use_sndfile=1
|
deps_packages="$deps_packages sndfile"
|
||||||
deps_packages+=" sndfile")
|
])
|
||||||
AC_DEFINE_UNQUOTED(USE_SNDFILE, $use_sndfile,
|
AC_DEFINE_UNQUOTED([USE_SNDFILE], [$use_sndfile],
|
||||||
[Define to 1 to enable sndfile support])
|
[Define to 1 to enable sndfile support])
|
||||||
|
|
||||||
# benchmarks
|
# benchmarks
|
||||||
AC_ARG_WITH([benchmarks],
|
AC_ARG_WITH([benchmarks], AS_HELP_STRING([--disable-benchmarks],
|
||||||
AS_HELP_STRING([--disable-benchmarks], [build without internal benchmarks]))
|
[build without internal benchmarks]))
|
||||||
AS_IF([test "x$with_benchmarks" == "xno"],
|
AS_IF([test "x$with_benchmarks" == "xno"], [
|
||||||
# then
|
use_benchmarks=0
|
||||||
use_benchmarks=0,
|
], [
|
||||||
# else
|
use_benchmarks=1
|
||||||
use_benchmarks=1)
|
])
|
||||||
AC_DEFINE_UNQUOTED(USE_BENCHMARKS, $use_benchmarks,
|
AC_DEFINE_UNQUOTED([USE_BENCHMARKS], [$use_benchmarks],
|
||||||
[Define to 1 to enable internal benchmarks])
|
[Define to 1 to enable internal benchmarks])
|
||||||
|
|
||||||
|
|
||||||
AC_MSG_RESULT([
|
AC_MSG_RESULT([
|
||||||
PKG_NAME PKG_VERSION configuration summary:
|
option summary:
|
||||||
--with-pulseaudio $with_pulseaudio ($use_pulseaudio)
|
alsa $with_alsa ($use_alsa)
|
||||||
--with-alsa $with_alsa ($use_alsa)
|
benchmarks $with_benchmarks ($use_benchmarks)
|
||||||
--with-sndfile $with_sndfile ($use_sndfile)
|
pulseaudio $with_pulseaudio ($use_pulseaudio)
|
||||||
--with-benchmarks $with_benchmarks ($use_benchmarks)
|
sndfile $with_sndfile ($use_sndfile)
|
||||||
deps_packages: $deps_packages
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
# Checks for libraries.
|
# Checks for libraries.
|
||||||
PKG_CHECK_MODULES(DEPS, [ $deps_packages ])
|
PKG_CHECK_MODULES(DEPS, [$deps_packages])
|
||||||
|
|
||||||
AC_SUBST(DEPS_CFLAGS)
|
|
||||||
AC_SUBST(DEPS_LIBS)
|
|
||||||
|
|
||||||
AC_SUBST([auto_find_tests], ['$(sort $(wildcard *.test))'])
|
AC_SUBST([auto_find_tests], ['$(sort $(wildcard *.test))'])
|
||||||
|
|
||||||
# Checks for header files.
|
AC_CONFIG_FILES([Makefile src/Makefile src/minimodem.1 tests/Makefile])
|
||||||
# AC_CHECK_HEADERS([stdlib.h string.h unistd.h])
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
|
||||||
# AC_HEADER_STDBOOL
|
|
||||||
# AC_TYPE_PID_T
|
|
||||||
|
|
||||||
# Checks for library functions.
|
|
||||||
# AC_FUNC_FORK
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([
|
|
||||||
Makefile
|
|
||||||
src/Makefile
|
|
||||||
src/minimodem.1
|
|
||||||
tests/Makefile
|
|
||||||
])
|
|
||||||
# testdata/Makefile
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
|
@ -1,3 +1,29 @@
|
||||||
|
minimodem (0.24-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
[ Chris Osborn ]
|
||||||
|
|
||||||
|
* Limit carrier/idle generation for input with delays
|
||||||
|
|
||||||
|
[ Kamal Mostafa ]
|
||||||
|
|
||||||
|
* Fix --tx float consistency: disable .wav "PEAK chunk" header
|
||||||
|
* Do not emit 0.5 sec flush for audio file output
|
||||||
|
* debian: bump standards-version=3.9.7 and debhelper-compat-version=9
|
||||||
|
|
||||||
|
[ Colin Ian King ]
|
||||||
|
|
||||||
|
* multiple static analysis and warnings fixes
|
||||||
|
|
||||||
|
-- Kamal Mostafa <kamal@whence.com> Sat, 23 Apr 2016 10:35:44 -0700
|
||||||
|
|
||||||
|
minimodem (0.23-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
[ Rodrigo Menezes ]
|
||||||
|
|
||||||
|
* TTY/TDD support
|
||||||
|
|
||||||
|
-- Kamal Mostafa <kamal@whence.com> Fri, 19 Feb 2016 13:05:07 -0800
|
||||||
|
|
||||||
minimodem (0.22.1-1) unstable; urgency=medium
|
minimodem (0.22.1-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Do not enable tx-carrier for non-interactive --file sessions
|
* Do not enable tx-carrier for non-interactive --file sessions
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
7
|
9
|
||||||
|
|
|
@ -2,8 +2,8 @@ Source: minimodem
|
||||||
Section: comm
|
Section: comm
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Kamal Mostafa <kamal@whence.com>
|
Maintainer: Kamal Mostafa <kamal@whence.com>
|
||||||
Build-Depends: debhelper (>= 7.0.50~), libfftw3-dev, libpulse-dev, libasound2-dev [linux-any], libsndfile1-dev
|
Build-Depends: debhelper (>= 9), libfftw3-dev, libpulse-dev, libasound2-dev [linux-any], libsndfile1-dev
|
||||||
Standards-Version: 3.9.6
|
Standards-Version: 3.9.7
|
||||||
Homepage: http://www.whence.com/minimodem
|
Homepage: http://www.whence.com/minimodem
|
||||||
Vcs-Git: https://github.com/kamalmostafa/minimodem.git
|
Vcs-Git: https://github.com/kamalmostafa/minimodem.git
|
||||||
Vcs-Browser: https://github.com/kamalmostafa/minimodem
|
Vcs-Browser: https://github.com/kamalmostafa/minimodem
|
||||||
|
@ -16,8 +16,8 @@ Description: general-purpose software audio FSK modem
|
||||||
Minimodem is a command-line program which decodes (or generates) audio
|
Minimodem is a command-line program which decodes (or generates) audio
|
||||||
modem tones at any specified baud rate, using various framing protocols.
|
modem tones at any specified baud rate, using various framing protocols.
|
||||||
It acts a general-purpose software FSK modem, and includes support for
|
It acts a general-purpose software FSK modem, and includes support for
|
||||||
various standard FSK protocols such as Bell103, Bell202, RTTY, NOAA SAME,
|
various standard FSK protocols such as Bell103, Bell202, RTTY, TTY/TDD,
|
||||||
and Caller-ID.
|
NOAA SAME, and Caller-ID.
|
||||||
.
|
.
|
||||||
Minimodem can play and capture audio modem tones in real-time via the
|
Minimodem can play and capture audio modem tones in real-time via the
|
||||||
system audio device, or in batched mode via audio files.
|
system audio device, or in batched mode via audio files.
|
||||||
|
|
|
@ -4,7 +4,7 @@ Upstream-Contact: Kamal Mostafa <kamal@whence.com>
|
||||||
Source: http://www.whence.com/minimodem
|
Source: http://www.whence.com/minimodem
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2011-2014 Kamal Mostafa <kamal@whence.com>
|
Copyright: 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
License: GPL-3.0+
|
License: GPL-3.0+
|
||||||
|
|
||||||
Files: src/*uic*
|
Files: src/*uic*
|
||||||
|
@ -12,7 +12,7 @@ Copyright: 2014 Marcos Vives Del Sol <socram8888@gmail.com>
|
||||||
License: GPL-3.0+
|
License: GPL-3.0+
|
||||||
|
|
||||||
Files: debian/*
|
Files: debian/*
|
||||||
Copyright: 2011-2014 Kamal Mostafa <kamal@whence.com>
|
Copyright: 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
License: GPL-3.0+
|
License: GPL-3.0+
|
||||||
|
|
||||||
License: GPL-3.0+
|
License: GPL-3.0+
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
# Makefile.am
|
# Makefile.am
|
||||||
#
|
#
|
||||||
# Copyright (C) 2011-2012 Kamal Mostafa <kamal@whence.com>
|
# Copyright (C) 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -194,7 +194,7 @@ baudot_encode_table[0x60][2] = {
|
||||||
* 1 LTRS state
|
* 1 LTRS state
|
||||||
* 2 FIGS state
|
* 2 FIGS state
|
||||||
*/
|
*/
|
||||||
static int baudot_charset = 0; // FIXME
|
static unsigned int baudot_charset = 0; // FIXME
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
18
src/fsk.c
18
src/fsk.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* fsk.c
|
* fsk.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011-2012 Kamal Mostafa <kamal@whence.com>
|
* Copyright (C) 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -62,7 +62,7 @@ fsk_plan_new(
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
debug_log("### b_mark=%u b_space=%u fftsize=%u\n",
|
debug_log("### b_mark=%u b_space=%u fftsize=%d\n",
|
||||||
fskp->b_mark, fskp->b_space, fskp->fftsize);
|
fskp->b_mark, fskp->b_space, fskp->fftsize);
|
||||||
|
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
||||||
assert( expect_bits[bitnum] == '1' || expect_bits[bitnum] == '0' );
|
assert( expect_bits[bitnum] == '1' || expect_bits[bitnum] == '0' );
|
||||||
|
|
||||||
bit_begin_sample = (float)(samples_per_bit * bitnum + 0.5f);
|
bit_begin_sample = (float)(samples_per_bit * bitnum + 0.5f);
|
||||||
debug_log( " bit# %2u @ %7u: ", bitnum, bit_begin_sample);
|
debug_log( " bit# %2d @ %7u: ", bitnum, bit_begin_sample);
|
||||||
fsk_bit_analyze(fskp, samples+bit_begin_sample, bit_nsamples,
|
fsk_bit_analyze(fskp, samples+bit_begin_sample, bit_nsamples,
|
||||||
&bit_values[bitnum],
|
&bit_values[bitnum],
|
||||||
&bit_sig_mags[bitnum],
|
&bit_sig_mags[bitnum],
|
||||||
|
@ -247,7 +247,7 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
||||||
if ( expect_bits[bitnum] != 'd' )
|
if ( expect_bits[bitnum] != 'd' )
|
||||||
continue;
|
continue;
|
||||||
bit_begin_sample = (float)(samples_per_bit * bitnum + 0.5f);
|
bit_begin_sample = (float)(samples_per_bit * bitnum + 0.5f);
|
||||||
debug_log( " bit# %2u @ %7u: ", bitnum, bit_begin_sample);
|
debug_log( " bit# %2d @ %7u: ", bitnum, bit_begin_sample);
|
||||||
fsk_bit_analyze(fskp, samples+bit_begin_sample, bit_nsamples,
|
fsk_bit_analyze(fskp, samples+bit_begin_sample, bit_nsamples,
|
||||||
&bit_values[bitnum],
|
&bit_values[bitnum],
|
||||||
&bit_sig_mags[bitnum],
|
&bit_sig_mags[bitnum],
|
||||||
|
@ -440,7 +440,7 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
||||||
for ( bitnum=0; bitnum<n_bits; bitnum++ )
|
for ( bitnum=0; bitnum<n_bits; bitnum++ )
|
||||||
*bits_outp |= (unsigned long long) bit_values[bitnum] << bitnum;
|
*bits_outp |= (unsigned long long) bit_values[bitnum] << bitnum;
|
||||||
|
|
||||||
debug_log(" frame algo=%u confidence=%f ampl=%f\n",
|
debug_log(" frame algo=%d confidence=%f ampl=%f\n",
|
||||||
CONFIDENCE_ALGO, confidence, *ampl_outp);
|
CONFIDENCE_ALGO, confidence, *ampl_outp);
|
||||||
return confidence;
|
return confidence;
|
||||||
}
|
}
|
||||||
|
@ -474,14 +474,14 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
|
||||||
int j;
|
int j;
|
||||||
for ( j=0; ; j++ )
|
for ( j=0; ; j++ )
|
||||||
{
|
{
|
||||||
int up = j%2 ? 1 : -1;
|
int up = ( j % 2 ) ? 1 : -1;
|
||||||
int t = try_first_sample + up*((j+1)/2)*try_step_nsamples;
|
int t = try_first_sample + up*((j+1)/2)*try_step_nsamples;
|
||||||
if ( t >= (int)try_max_nsamples )
|
if ( t >= (int)try_max_nsamples )
|
||||||
break;
|
break;
|
||||||
if ( t < 0 )
|
if ( t < 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float c, ampl_out;
|
float c, ampl_out = 0.0;
|
||||||
unsigned long long bits_out = 0;
|
unsigned long long bits_out = 0;
|
||||||
debug_log("try fsk_frame_analyze at t=%d\n", t);
|
debug_log("try fsk_frame_analyze at t=%d\n", t);
|
||||||
c = fsk_frame_analyze(fskp, samples+t, samples_per_bit,
|
c = fsk_frame_analyze(fskp, samples+t, samples_per_bit,
|
||||||
|
@ -525,8 +525,8 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
|
||||||
|
|
||||||
debug_log("FSK_FRAME bits='");
|
debug_log("FSK_FRAME bits='");
|
||||||
for ( j=0; j<expect_n_bits; j++ )
|
for ( j=0; j<expect_n_bits; j++ )
|
||||||
debug_log("%c", ( *bits_outp >> j ) & 1 ? '1' : '0' );
|
debug_log("%c", ( ( *bits_outp >> j ) & 1 ) ? '1' : '0' );
|
||||||
debug_log("' datum='%c' (0x%02x) c=%f a=%f t=%d\n",
|
debug_log("' datum='%c' (0x%02x) c=%f a=%f t=%u\n",
|
||||||
isprint(bitchar)||isspace(bitchar) ? bitchar : '.',
|
isprint(bitchar)||isspace(bitchar) ? bitchar : '.',
|
||||||
bitchar,
|
bitchar,
|
||||||
confidence, best_a, best_t);
|
confidence, best_a, best_t);
|
||||||
|
|
|
@ -30,8 +30,8 @@ minimodem \- general-purpose software audio FSK modem
|
||||||
is a command-line program which decodes (or generates) audio
|
is a command-line program which decodes (or generates) audio
|
||||||
modem tones at any specified baud rate, using various framing protocols.
|
modem tones at any specified baud rate, using various framing protocols.
|
||||||
It acts a general-purpose software FSK modem, and includes support for
|
It acts a general-purpose software FSK modem, and includes support for
|
||||||
various standard FSK protocols such as Bell103, Bell202, RTTY, NOAA SAME,
|
various standard FSK protocols such as Bell103, Bell202, RTTY, TTY/TDD,
|
||||||
and Caller-ID.
|
NOAA SAME, and Caller-ID.
|
||||||
.PP
|
.PP
|
||||||
.B Minimodem
|
.B Minimodem
|
||||||
can play and capture audio modem tones in real-time via the system
|
can play and capture audio modem tones in real-time via the system
|
||||||
|
@ -67,6 +67,9 @@ default mark and space tone frequencies.
|
||||||
.B rtty
|
.B rtty
|
||||||
: RTTY 45.45 bps \-\-baudot \-\-stopbits 1.5
|
: RTTY 45.45 bps \-\-baudot \-\-stopbits 1.5
|
||||||
.TP
|
.TP
|
||||||
|
.B tdd
|
||||||
|
: TTY/TDD 45.45 bps \-\-baudot \-\-stopbits 2.0
|
||||||
|
.TP
|
||||||
.B same
|
.B same
|
||||||
: SAME 520.83 bps \-\-startbits 0 \-\-stopbits 0 \-\-sync-byte 0xAB
|
: SAME 520.83 bps \-\-startbits 0 \-\-stopbits 0 \-\-sync-byte 0xAB
|
||||||
.br
|
.br
|
||||||
|
@ -187,6 +190,9 @@ Filter the received text output, replacing any "non-printable" bytes
|
||||||
with a '.' character.
|
with a '.' character.
|
||||||
(This option applies to \-\-rx mode only).
|
(This option applies to \-\-rx mode only).
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-print-eot
|
||||||
|
Print "### EOT" to stderr after each transmit completes.
|
||||||
|
.TP
|
||||||
.B \-\-tx-carrier
|
.B \-\-tx-carrier
|
||||||
When transmitting from a blocking source, keep a carrier going while waiting
|
When transmitting from a blocking source, keep a carrier going while waiting
|
||||||
for more data.
|
for more data.
|
||||||
|
@ -233,7 +239,7 @@ The latest version is available at <http://www.whence.com/minimodem>.
|
||||||
.B minimodem
|
.B minimodem
|
||||||
was written by Kamal Mostafa <kamal@whence.com>.
|
was written by Kamal Mostafa <kamal@whence.com>.
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
Copyright \(co 2011-2014 by Kamal Mostafa <kamal@whence.com>.
|
Copyright \(co 2011-2016 by Kamal Mostafa <kamal@whence.com>.
|
||||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||||
.br
|
.br
|
||||||
This is free software: you are free to change and redistribute it.
|
This is free software: you are free to change and redistribute it.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* minimodem - software audio Bell-type or RTTY FSK modem
|
* minimodem - software audio Bell-type or RTTY FSK modem
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011-2014 Kamal Mostafa <kamal@whence.com>
|
* Copyright (C) 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -46,12 +46,14 @@
|
||||||
char *program_name = "";
|
char *program_name = "";
|
||||||
|
|
||||||
int tx_transmitting = 0;
|
int tx_transmitting = 0;
|
||||||
|
int tx_print_eot = 0;
|
||||||
int tx_leader_bits_len = 2;
|
int tx_leader_bits_len = 2;
|
||||||
int tx_trailer_bits_len = 2;
|
int tx_trailer_bits_len = 2;
|
||||||
|
|
||||||
simpleaudio *tx_sa_out;
|
simpleaudio *tx_sa_out;
|
||||||
float tx_bfsk_mark_f;
|
float tx_bfsk_mark_f;
|
||||||
unsigned int tx_bit_nsamples;
|
unsigned int tx_bit_nsamples;
|
||||||
|
unsigned int tx_flush_nsamples;
|
||||||
|
|
||||||
void
|
void
|
||||||
tx_stop_transmit_sighandler( int sig )
|
tx_stop_transmit_sighandler( int sig )
|
||||||
|
@ -62,11 +64,12 @@ tx_stop_transmit_sighandler( int sig )
|
||||||
for ( j=0; j<tx_trailer_bits_len; j++ )
|
for ( j=0; j<tx_trailer_bits_len; j++ )
|
||||||
simpleaudio_tone(tx_sa_out, tx_bfsk_mark_f, tx_bit_nsamples);
|
simpleaudio_tone(tx_sa_out, tx_bfsk_mark_f, tx_bit_nsamples);
|
||||||
|
|
||||||
// 0.5 sec of zero samples to flush - FIXME lame
|
if ( tx_flush_nsamples )
|
||||||
size_t sample_rate = simpleaudio_get_rate(tx_sa_out);
|
simpleaudio_tone(tx_sa_out, 0, tx_flush_nsamples);
|
||||||
simpleaudio_tone(tx_sa_out, 0, sample_rate/2);
|
|
||||||
|
|
||||||
tx_transmitting = 0;
|
tx_transmitting = 0;
|
||||||
|
if ( tx_print_eot )
|
||||||
|
fprintf(stderr, "### EOT\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,6 +133,10 @@ static void fsk_transmit_stdin(
|
||||||
tx_sa_out = sa_out;
|
tx_sa_out = sa_out;
|
||||||
tx_bfsk_mark_f = bfsk_mark_f;
|
tx_bfsk_mark_f = bfsk_mark_f;
|
||||||
tx_bit_nsamples = bit_nsamples;
|
tx_bit_nsamples = bit_nsamples;
|
||||||
|
if ( tx_interactive )
|
||||||
|
tx_flush_nsamples = sample_rate/2; // 0.5 sec of zero samples to flush
|
||||||
|
else
|
||||||
|
tx_flush_nsamples = 0;
|
||||||
|
|
||||||
// one-shot
|
// one-shot
|
||||||
struct itimerval itv = {
|
struct itimerval itv = {
|
||||||
|
@ -142,6 +149,9 @@ static void fsk_transmit_stdin(
|
||||||
{0, 0} // it_value
|
{0, 0} // it_value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// arbitrary chosen timeout value: 1/25 of a second
|
||||||
|
unsigned int idle_carrier_usec = (1000000/25);
|
||||||
|
|
||||||
int block_input = tx_interactive && !txcarrier;
|
int block_input = tx_interactive && !txcarrier;
|
||||||
if ( block_input )
|
if ( block_input )
|
||||||
signal(SIGALRM, tx_stop_transmit_sighandler);
|
signal(SIGALRM, tx_stop_transmit_sighandler);
|
||||||
|
@ -159,8 +169,16 @@ static void fsk_transmit_stdin(
|
||||||
{
|
{
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(fd, &fdset);
|
FD_SET(fd, &fdset);
|
||||||
struct timeval tv_zero = { 0, 0 };
|
struct timeval tv_idletimeout = { 0, 0 };
|
||||||
if( block_input || select(fd+1, &fdset, NULL, NULL, &tv_zero) )
|
|
||||||
|
if ( !tx_interactive ) {
|
||||||
|
// When stdin blocks we "emit idle tone", for a duration of
|
||||||
|
// idle_carrier_usec. If !tx_interactive (i.e. writing to an
|
||||||
|
// audio file) make the select timeout the same duration.
|
||||||
|
tv_idletimeout.tv_usec = idle_carrier_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( block_input || select(fd+1, &fdset, NULL, NULL, &tv_idletimeout) )
|
||||||
{
|
{
|
||||||
n_read = read(fd, &buf, sizeof(buf));
|
n_read = read(fd, &buf, sizeof(buf));
|
||||||
if( n_read <= 0 ) //Includes EOF (0) and errors (-1)
|
if( n_read <= 0 ) //Includes EOF (0) and errors (-1)
|
||||||
|
@ -211,10 +229,10 @@ static void fsk_transmit_stdin(
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tx_transmitting = 1;
|
tx_transmitting = 1;
|
||||||
unsigned int j;
|
|
||||||
/* emit idle tone (mark) */
|
/* emit idle tone (mark) */
|
||||||
for ( j=0; j<tx_leader_bits_len; j++ )
|
simpleaudio_tone(sa_out,
|
||||||
simpleaudio_tone(sa_out, invert_start_stop ? bfsk_space_f : bfsk_mark_f, sample_rate/50);
|
invert_start_stop ? bfsk_space_f : bfsk_mark_f,
|
||||||
|
idle_carrier_usec * sample_rate / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( block_input )
|
if ( block_input )
|
||||||
|
@ -360,7 +378,7 @@ version()
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
"minimodem %s\n"
|
"minimodem %s\n"
|
||||||
"Copyright (C) 2011-2014 Kamal Mostafa <kamal@whence.com>\n"
|
"Copyright (C) 2011-2016 Kamal Mostafa <kamal@whence.com>\n"
|
||||||
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
|
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
|
||||||
"This is free software: you are free to change and redistribute it.\n"
|
"This is free software: you are free to change and redistribute it.\n"
|
||||||
"There is NO WARRANTY, to the extent permitted by law.\n\n"
|
"There is NO WARRANTY, to the extent permitted by law.\n\n"
|
||||||
|
@ -403,12 +421,14 @@ usage()
|
||||||
" --binary-output\n"
|
" --binary-output\n"
|
||||||
" --binary-raw {nbits}\n"
|
" --binary-raw {nbits}\n"
|
||||||
" --print-filter\n"
|
" --print-filter\n"
|
||||||
|
" --print-eot\n"
|
||||||
" --tx-carrier\n"
|
" --tx-carrier\n"
|
||||||
" {baudmode}\n"
|
" {baudmode}\n"
|
||||||
" any_number_N Bell-like N bps --ascii\n"
|
" any_number_N Bell-like N bps --ascii\n"
|
||||||
" 1200 Bell202 1200 bps --ascii\n"
|
" 1200 Bell202 1200 bps --ascii\n"
|
||||||
" 300 Bell103 300 bps --ascii\n"
|
" 300 Bell103 300 bps --ascii\n"
|
||||||
" rtty RTTY 45.45 bps --baudot --stopbits=1.5\n"
|
" rtty RTTY 45.45 bps --baudot --stopbits=1.5\n"
|
||||||
|
" tdd TTY/TDD 45.45 bps --baudot --stopbits=2.0\n"
|
||||||
" same NOAA SAME 520.83 bps --sync-byte=0xAB ...\n"
|
" same NOAA SAME 520.83 bps --sync-byte=0xAB ...\n"
|
||||||
" callerid Bell202 CID 1200 bps\n"
|
" callerid Bell202 CID 1200 bps\n"
|
||||||
" uic{-train,-ground} UIC-751-3 Train/Ground 600 bps\n"
|
" uic{-train,-ground} UIC-751-3 Train/Ground 600 bps\n"
|
||||||
|
@ -561,6 +581,7 @@ main( int argc, char*argv[] )
|
||||||
MINIMODEM_OPT_BINARY_RAW,
|
MINIMODEM_OPT_BINARY_RAW,
|
||||||
MINIMODEM_OPT_PRINT_FILTER,
|
MINIMODEM_OPT_PRINT_FILTER,
|
||||||
MINIMODEM_OPT_XRXNOISE,
|
MINIMODEM_OPT_XRXNOISE,
|
||||||
|
MINIMODEM_OPT_PRINT_EOT,
|
||||||
MINIMODEM_OPT_TXCARRIER
|
MINIMODEM_OPT_TXCARRIER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -600,6 +621,7 @@ main( int argc, char*argv[] )
|
||||||
{ "binary-output", 0, 0, MINIMODEM_OPT_BINARY_OUTPUT },
|
{ "binary-output", 0, 0, MINIMODEM_OPT_BINARY_OUTPUT },
|
||||||
{ "binary-raw", 1, 0, MINIMODEM_OPT_BINARY_RAW },
|
{ "binary-raw", 1, 0, MINIMODEM_OPT_BINARY_RAW },
|
||||||
{ "print-filter", 0, 0, MINIMODEM_OPT_PRINT_FILTER },
|
{ "print-filter", 0, 0, MINIMODEM_OPT_PRINT_FILTER },
|
||||||
|
{ "print-eot", 0, 0, MINIMODEM_OPT_PRINT_EOT },
|
||||||
{ "Xrxnoise", 1, 0, MINIMODEM_OPT_XRXNOISE },
|
{ "Xrxnoise", 1, 0, MINIMODEM_OPT_XRXNOISE },
|
||||||
{ "tx-carrier", 0, 0, MINIMODEM_OPT_TXCARRIER },
|
{ "tx-carrier", 0, 0, MINIMODEM_OPT_TXCARRIER },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
|
@ -733,6 +755,9 @@ main( int argc, char*argv[] )
|
||||||
case MINIMODEM_OPT_TXCARRIER:
|
case MINIMODEM_OPT_TXCARRIER:
|
||||||
txcarrier = 1;
|
txcarrier = 1;
|
||||||
break;
|
break;
|
||||||
|
case MINIMODEM_OPT_PRINT_EOT:
|
||||||
|
tx_print_eot = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
@ -781,6 +806,16 @@ main( int argc, char*argv[] )
|
||||||
bfsk_n_data_bits = 5;
|
bfsk_n_data_bits = 5;
|
||||||
if ( bfsk_nstopbits < 0 )
|
if ( bfsk_nstopbits < 0 )
|
||||||
bfsk_nstopbits = 1.5;
|
bfsk_nstopbits = 1.5;
|
||||||
|
} else if ( strncasecmp(modem_mode, "tdd",4)==0 ) {
|
||||||
|
bfsk_databits_decode = databits_decode_baudot;
|
||||||
|
bfsk_databits_encode = databits_encode_baudot;
|
||||||
|
bfsk_data_rate = 45.45;
|
||||||
|
if ( bfsk_n_data_bits == 0 )
|
||||||
|
bfsk_n_data_bits = 5;
|
||||||
|
if ( bfsk_nstopbits < 0 )
|
||||||
|
bfsk_nstopbits = 2.0;
|
||||||
|
bfsk_mark_f = 1400;
|
||||||
|
bfsk_space_f = 1800;
|
||||||
} else if ( strncasecmp(modem_mode, "same",5)==0 ) {
|
} else if ( strncasecmp(modem_mode, "same",5)==0 ) {
|
||||||
// http://www.nws.noaa.gov/nwr/nwrsame.htm
|
// http://www.nws.noaa.gov/nwr/nwrsame.htm
|
||||||
bfsk_data_rate = 520.0 + 5/6.0;
|
bfsk_data_rate = 520.0 + 5/6.0;
|
||||||
|
@ -1100,7 +1135,7 @@ main( int argc, char*argv[] )
|
||||||
assert ( samples_nvalid + read_nsamples <= samplebuf_size );
|
assert ( samples_nvalid + read_nsamples <= samplebuf_size );
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
r = simpleaudio_read(sa, samples_readptr, read_nsamples);
|
r = simpleaudio_read(sa, samples_readptr, read_nsamples);
|
||||||
debug_log("simpleaudio_read(samplebuf+%zd, n=%zu) returns %zd\n",
|
debug_log("simpleaudio_read(samplebuf+%td, n=%zu) returns %zd\n",
|
||||||
samples_readptr - samplebuf, read_nsamples, r);
|
samples_readptr - samplebuf, read_nsamples, r);
|
||||||
if ( r < 0 ) {
|
if ( r < 0 ) {
|
||||||
fprintf(stderr, "simpleaudio_read: error\n");
|
fprintf(stderr, "simpleaudio_read: error\n");
|
||||||
|
@ -1363,7 +1398,7 @@ main( int argc, char*argv[] )
|
||||||
if (bfsk_msb_first) {
|
if (bfsk_msb_first) {
|
||||||
bits = bit_reverse(bits, bfsk_n_data_bits);
|
bits = bit_reverse(bits, bfsk_n_data_bits);
|
||||||
}
|
}
|
||||||
debug_log("Input: %08x%08x - Databits: %i - Shift: %i\n", (unsigned int)(bits >> 32), (unsigned int)bits, bfsk_n_data_bits, bfsk_nstartbits);
|
debug_log("Input: %08x%08x - Databits: %u - Shift: %i\n", (unsigned int)(bits >> 32), (unsigned int)bits, bfsk_n_data_bits, bfsk_nstartbits);
|
||||||
|
|
||||||
unsigned int dataout_size = 4096;
|
unsigned int dataout_size = 4096;
|
||||||
char dataoutbuf[4096];
|
char dataoutbuf[4096];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* simple-tone-generator.c
|
* simple-tone-generator.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011-2012 Kamal Mostafa <kamal@whence.com>
|
* Copyright (C) 2011-2016 Kamal Mostafa <kamal@whence.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -200,6 +200,15 @@ sa_sndfile_open_stream(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable the insertion of this questionable "PEAK chunk" header thing.
|
||||||
|
// Relates only to writing SF_FORMAT_FLOAT .wav and .aiff files
|
||||||
|
// (minimodem --tx --float-samples). When left enabled, this adds some
|
||||||
|
// wonky bytes to the header which change from run to run (different every
|
||||||
|
// wall-clock second. WTF?
|
||||||
|
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_ADD_PEAK_CHUNK
|
||||||
|
/* Turn off the PEAK chunk. */
|
||||||
|
sf_command(s, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE);
|
||||||
|
|
||||||
/* good or bad to override these? */
|
/* good or bad to override these? */
|
||||||
sa->rate = sfinfo.samplerate;
|
sa->rate = sfinfo.samplerate;
|
||||||
sa->channels = sfinfo.channels;
|
sa->channels = sfinfo.channels;
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
MINIMODEM="${MINIMODEM-./minimodem}"
|
||||||
|
[ -f "$MINIMODEM" ] || {
|
||||||
|
MINIMODEM="../src/minimodem"
|
||||||
|
[ -f "$MINIMODEM" ] || {
|
||||||
|
echo "E: cannot find minimodem in ./ or ../src/" 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
minimodem_tx_args="1200 $1"
|
||||||
|
|
||||||
|
textfile="testdata-ascii.txt"
|
||||||
|
|
||||||
|
TMPF="/tmp/minimodem-test-$$"
|
||||||
|
trap "rm -f $TMPF.*" 0
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
$MINIMODEM --tx --file $TMPF.1.wav $minimodem_tx_args < "$textfile"
|
||||||
|
sleep 1
|
||||||
|
$MINIMODEM --tx --file $TMPF.2.wav $minimodem_tx_args < "$textfile"
|
||||||
|
sleep 1
|
||||||
|
$MINIMODEM --tx --file $TMPF.3.wav $minimodem_tx_args < "$textfile"
|
||||||
|
|
||||||
|
cmp -s $TMPF.1.wav $TMPF.2.wav || {
|
||||||
|
echo -e "TX-NOT-CONSISTENT"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp -s $TMPF.1.wav $TMPF.3.wav || {
|
||||||
|
echo -e "TX-NOT-CONSISTENT"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
stats="three runs of '--tx $minimodem_tx_args' created identical output"
|
||||||
|
|
||||||
|
result="OK "
|
||||||
|
exitcode=0
|
||||||
|
|
||||||
|
echo -e "$result $stats"
|
||||||
|
|
||||||
|
exit $exitcode
|
|
@ -0,0 +1 @@
|
||||||
|
exec ./16-verify-tx-consistent.test --float-samples
|
|
@ -0,0 +1 @@
|
||||||
|
exec ./self-test testdata-baudot.txt tdd
|
|
@ -15,34 +15,3 @@ the quick brown fox jumps over the lazy dog
|
||||||
Earning our SkyMiles
|
Earning our SkyMiles
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
minimodem - software audio Bell-type or RTTY FSK modem
|
|
||||||
Copyright (C) 2011-2012 Kamal Mostafa <kamal@whence.com>
|
|
||||||
|
|
||||||
Minimodem is a command-line program which generates (or decodes) audio
|
|
||||||
modem tones at any specified baud rate, emulating an old Bell-type or
|
|
||||||
radio-teletype FSK modem. The tones can be played to (or recorded from)
|
|
||||||
the system audio (PulseAudio or ALSA) or to an audio file.
|
|
||||||
|
|
||||||
Minimodem can be used to transfer data between nearby computers using an
|
|
||||||
audio cable (or just via sound waves), or between remote computers using
|
|
||||||
radio, telephone, or another audio communications medium.
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
minimodem - software audio Bell-type or RTTY FSK modem
|
|
||||||
Copyright (C) 2011-2012 Kamal Mostafa <kamal@whence.com>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue