From ef8a75f10e713f022024022030a83793b8e2881b Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 4 Feb 2015 08:16:12 +0200 Subject: [PATCH] main: refactor send and recv --- amodem-cli | 10 +++---- amodem/main.py | 68 ++++++++++++++++++++++++++++++++++++++++++ amodem/recv.py | 36 ---------------------- amodem/send.py | 29 ------------------ tests/test_transfer.py | 7 ++--- 5 files changed, 76 insertions(+), 74 deletions(-) create mode 100644 amodem/main.py diff --git a/amodem-cli b/amodem-cli index feb0bcb..b25463c 100755 --- a/amodem-cli +++ b/amodem-cli @@ -19,7 +19,7 @@ except ImportError: log = logging.getLogger('__name__') -from amodem import recv, send, calib, audio, async +from amodem import main, calib, audio, async from amodem.config import bitrates bitrate = os.environ.get('BITRATE', 1) @@ -96,7 +96,7 @@ def get_volume_cmd(args): return c[args.command] -def main(): +def _main(): fmt = ('Audio OFDM MODEM: {0:.1f} kb/s ({1:d}-QAM x {2:d} carriers) ' 'Fs={3:.1f} kHz') description = fmt.format(config.modem_bps / 1e3, len(config.symbols), @@ -118,7 +118,7 @@ def main(): '-o', '--output', help='output file (use "-" for stdout).' ' if not specified, `aplay` tool will be used.') sender.set_defaults( - main=lambda config, args: send.main( + main=lambda config, args: main.send( config, src=wrap(Compressor, args.src, args.zip), dst=args.dst ), calib=lambda config, args: calib.send( @@ -145,7 +145,7 @@ def main(): '--plot', action='store_true', default=False, help='plot results using pylab module') receiver.set_defaults( - main=lambda config, args: recv.main( + main=lambda config, args: main.recv( config, src=args.src, dst=wrap(Decompressor, args.dst, args.zip), pylab=args.pylab, dump_audio=args.dump ), @@ -213,5 +213,5 @@ def main(): if __name__ == '__main__': - success = main() + success = _main() sys.exit(0 if success else 1) diff --git a/amodem/main.py b/amodem/main.py new file mode 100644 index 0000000..f593013 --- /dev/null +++ b/amodem/main.py @@ -0,0 +1,68 @@ +import numpy as np +import logging +import itertools +from . import send as _send +from . import recv as _recv +from . import framing, common, stream, detect, sampling + +log = logging.getLogger(__name__) + + +def send(config, src, dst): + sender = _send.Sender(dst, config=config) + Fs = config.Fs + + # pre-padding audio with silence (priming the audio sending queue) + sender.write(np.zeros(int(Fs * config.silence_start))) + + sender.start() + + training_duration = sender.offset + log.info('Sending %.3f seconds of training audio', training_duration / Fs) + + reader = stream.Reader(src, eof=True) + data = itertools.chain.from_iterable(reader) + bits = framing.encode(data) + log.info('Starting modulation') + sender.modulate(bits=bits) + + data_duration = sender.offset - training_duration + log.info('Sent %.3f kB @ %.3f seconds', + reader.total / 1e3, data_duration / Fs) + + # post-padding audio with silence + sender.write(np.zeros(int(Fs * config.silence_stop))) + return True + + +def recv(config, src, dst, dump_audio=None, pylab=None): + if dump_audio: + src = stream.Dumper(src, dump_audio) + reader = stream.Reader(src, data_type=common.loads) + signal = itertools.chain.from_iterable(reader) + + log.debug('Skipping %.3f seconds', config.skip_start) + common.take(signal, int(config.skip_start * config.Fs)) + + pylab = pylab or common.Dummy() + detector = detect.Detector(config=config, pylab=pylab) + receiver = _recv.Receiver(config=config, pylab=pylab) + try: + log.info('Waiting for carrier tone: %.1f kHz', config.Fc / 1e3) + signal, amplitude, freq_error = detector.run(signal) + + freq = 1 / (1.0 + freq_error) # receiver's compensated frequency + log.debug('Frequency correction: %.3f ppm', (freq - 1) * 1e6) + + gain = 1.0 / amplitude + log.debug('Gain correction: %.3f', gain) + + sampler = sampling.Sampler(signal, sampling.Interpolator(), freq=freq) + receiver.run(sampler, gain=1.0/amplitude, output=dst) + return True + except BaseException: + log.exception('Decoding failed') + return False + finally: + dst.flush() + receiver.report() diff --git a/amodem/recv.py b/amodem/recv.py index 120b9dd..d79591d 100644 --- a/amodem/recv.py +++ b/amodem/recv.py @@ -6,13 +6,10 @@ import time log = logging.getLogger(__name__) -from . import stream from . import dsp -from . import sampling from . import common from . import framing from . import equalizer -from . import detect class Receiver(object): @@ -193,36 +190,3 @@ class Receiver(object): self.plt.axis('equal') self.plt.axis(np.array([-1, 1, -1, 1])*1.1) self.plt.title(title) - - -def main(config, src, dst, dump_audio=None, pylab=None): - if dump_audio: - src = stream.Dumper(src, dump_audio) - reader = stream.Reader(src, data_type=common.loads) - signal = itertools.chain.from_iterable(reader) - - log.debug('Skipping %.3f seconds', config.skip_start) - common.take(signal, int(config.skip_start * config.Fs)) - - pylab = pylab or common.Dummy() - detector = detect.Detector(config=config, pylab=pylab) - receiver = Receiver(config=config, pylab=pylab) - try: - log.info('Waiting for carrier tone: %.1f kHz', config.Fc / 1e3) - signal, amplitude, freq_error = detector.run(signal) - - freq = 1 / (1.0 + freq_error) # receiver's compensated frequency - log.debug('Frequency correction: %.3f ppm', (freq - 1) * 1e6) - - gain = 1.0 / amplitude - log.debug('Gain correction: %.3f', gain) - - sampler = sampling.Sampler(signal, sampling.Interpolator(), freq=freq) - receiver.run(sampler, gain=1.0/amplitude, output=dst) - return True - except BaseException: - log.exception('Decoding failed') - return False - finally: - dst.flush() - receiver.report() diff --git a/amodem/send.py b/amodem/send.py index 5e52d98..95eb85e 100644 --- a/amodem/send.py +++ b/amodem/send.py @@ -5,8 +5,6 @@ import itertools log = logging.getLogger(__name__) from . import common -from . import stream -from . import framing from . import equalizer from . import dsp @@ -48,30 +46,3 @@ class Sender(object): if i % self.iters_per_report == 0: total_bits = i * Nfreq * self.modem.bits_per_symbol log.debug('Sent %10.3f kB', total_bits / 8e3) - - -def main(config, src, dst): - sender = Sender(dst, config=config) - Fs = config.Fs - - # pre-padding audio with silence (priming the audio sending queue) - sender.write(np.zeros(int(Fs * config.silence_start))) - - sender.start() - - training_duration = sender.offset - log.info('Sending %.3f seconds of training audio', training_duration / Fs) - - reader = stream.Reader(src, eof=True) - data = itertools.chain.from_iterable(reader) - bits = framing.encode(data) - log.info('Starting modulation') - sender.modulate(bits=bits) - - data_duration = sender.offset - training_duration - log.info('Sent %.3f kB @ %.3f seconds', - reader.total / 1e3, data_duration / Fs) - - # post-padding audio with silence - sender.write(np.zeros(int(Fs * config.silence_stop))) - return True diff --git a/tests/test_transfer.py b/tests/test_transfer.py index c57aa93..5c0a842 100644 --- a/tests/test_transfer.py +++ b/tests/test_transfer.py @@ -3,8 +3,7 @@ from io import BytesIO import numpy as np -from amodem import send -from amodem import recv +from amodem import main from amodem import common from amodem import dsp from amodem import sampling @@ -30,7 +29,7 @@ class Args(object): def run(size, chan=None, df=0, success=True, reader=None): tx_data = os.urandom(size) tx_audio = BytesIO() - send.main(config=config, src=BytesIO(tx_data), dst=tx_audio) + main.send(config=config, src=BytesIO(tx_data), dst=tx_audio) data = tx_audio.getvalue() data = common.loads(data) @@ -49,7 +48,7 @@ def run(size, chan=None, df=0, success=True, reader=None): if reader: rx_audio = reader(rx_audio) try: - result = recv.main(config=config, src=rx_audio, dst=rx_data, + result = main.recv(config=config, src=rx_audio, dst=rx_data, dump_audio=dump) finally: rx_audio.close()