diff options
| author | Sebastian Muszytowski <sebastian@muszytowski.net> | 2016-01-14 21:11:29 +0100 | 
|---|---|---|
| committer | Sebastian Muszytowski <sebastian@muszytowski.net> | 2016-01-14 21:11:29 +0100 | 
| commit | e63ecbb75dafeb19de9a0eea8a6b228f0752ee37 (patch) | |
| tree | 248ce06ec2fbd5a88084412f61feb1c97d40c329 | |
| parent | ff61107b89ddeee39a32a94182a4bdeeabebf7fb (diff) | |
add tagsu-avr-modem from Rakettitiede Oy
| -rw-r--r-- | modem.c | 95 | ||||
| -rw-r--r-- | modem.h | 24 | ||||
| -rw-r--r-- | utilities/modem.py | 111 | 
3 files changed, 230 insertions, 0 deletions
| @@ -0,0 +1,95 @@ +/* Name: modem.c + * + * Audio modem for Attiny85 & other AVR chips with modifications + * + * Author: Jari Tulilahti + * Copyright: 2014 Rakettitiede Oy + * License: LGPLv3, see COPYING, and COPYING.LESSER -files for more info + */ + +#include "modem.h" + +/* Ring buffer global variables */ +static volatile uint8_t modem_buffer_head = 0, modem_buffer_tail = 0; +static volatile uint8_t modem_buffer[MODEM_BUFFER_SIZE]; + +/* + * Returns number of available bytes in ringbuffer or 0 if empty + */ +uint8_t modem_buffer_available() { +	return modem_buffer_head - modem_buffer_tail; +} + +/* + * Store 1 byte in ringbuffer + */ +static inline void modem_buffer_put(const uint8_t c) { +	if (modem_buffer_available() != MODEM_BUFFER_SIZE) {  +		modem_buffer[modem_buffer_head++ % MODEM_BUFFER_SIZE] = c; +	}  +} + +/* + * Fetch 1 byte from ringbuffer + */ +uint8_t modem_buffer_get() { +	uint8_t b = 0; +	if (modem_buffer_available() != 0) { +		b = modem_buffer[modem_buffer_tail++ % MODEM_BUFFER_SIZE]; +	} +	return b; +} + +/* + * Pin Change Interrupt Vector. This is The Modem. + */ +ISR(PCINT0_vect) { +	/* Static variables instead of globals to keep scope inside ISR */ +	static uint8_t modem_bit = 0; +	static uint8_t modem_bitlen = 0; +	static uint8_t modem_byte = 0; + +	/* Read & Zero Timer/Counter 1 value */ +	uint8_t modem_pulselen = MODEM_TIMER; +	MODEM_TIMER = 0; + +	/* +	 * Check if we received Start/Sync -pulse. +	 * Calculate bit signal length middle point from pulse. +	 * Return from ISR immediately. +	 */ +	if (modem_pulselen > MODEM_SYNC_LEN) { +		modem_bitlen = (modem_pulselen >> 2); +		modem_bit = 0; +		return; +	} + +	/* +	 * Shift byte and set high bit according to the pulse length. +	 * Long pulse = 1, Short pulse = 0 +	 */ +	modem_byte = (modem_byte >> 1) | (modem_pulselen < modem_bitlen ? 0x00 : 0x80); + +	/* Check if we received complete byte and store it in ring buffer */ +	if (!(++modem_bit % 0x08)) { +		modem_buffer_put(modem_byte); +	} +} + +/* + * Start the modem by enabling Pin Change Interrupts & Timer + */ +void modem_init()  { +	/* Modem pin as input */ +	MODEM_DDR &= ~(1 << MODEM_PIN); + +	/* Enable Pin Change Interrupts and PCINT for MODEM_PIN */ +	GIMSK |= (1 << PCIE); +	PCMSK |= (1 << MODEM_PIN); + +	/* Timer: TCCR1: CS10, CS11 and CS12 bits: 8MHz clock with Prescaler 64 = 125kHz timer clock */ +	TCCR1 = (1 << CS10) | (1 << CS11) | (1 << CS12); + +	/* Enable interrupts */ +	sei(); +}  @@ -0,0 +1,24 @@ +/* Name: modem.h + * Author: Jari Tulilahti + * Copyright: 2014 Rakettitiede Oy + * License: LGPLv3, see COPYING, and COPYING.LESSER -files for more info + */ + +#pragma once + +#include <avr/interrupt.h> +#include <stdlib.h> + +/* Modem ring buffer size must be power of 2 */ +#define MODEM_BUFFER_SIZE	4 + +/* Modem defines */ +#define MODEM_SYNC_LEN		42 +#define MODEM_TIMER		TCNT1 +#define MODEM_PIN 		PCINT3 +#define MODEM_DDR		DDRB + +/* Public funtions */ +uint8_t modem_buffer_available(); +uint8_t modem_buffer_get(); +void modem_init(); diff --git a/utilities/modem.py b/utilities/modem.py new file mode 100644 index 0000000..f2e2b1b --- /dev/null +++ b/utilities/modem.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python + +import sys, wave + +# +# "Modem" wav creator for "Next Gen" Tagsu Modem :) +# +# Author: Jari Tulilahti +# Copyright: 2014 Rakettitiede Oy +# License: LGPLv3, see COPYING and COPYING.LESSER -files for more info +# +# Usage: +#	python modem.py <input_filename> [output_wav_filename] [samplerate] +# +# Default sample rate is 48000 +# Default output to stdout if no wav filename given +# +# Working sample rates are between 16000 - 48000: +# +# 16000 (~4000 bps) +# 22050 (~5500 bps) +# 24000 (~6000 bps) +# 32000 (~8000 bps) +# 44100 (~11025 bps) +# 48000 (~12000 bps) +# +# NOTICE: +# +# Actual speed depends of the data, as zeroes and ones take +# different amount of samples, the more zeros, the faster the speed. +# Average bps has been calculated using data "0101010101..." +# + +class modem: + +	bits = [[3 * chr(0), 5 * chr(0)], [3 * chr(255), 5 * chr(255)]] +	sync = [17 * chr(0), 17 * chr(255)] +	hilo = 0 + +	# Nothing here +	def __init__(self): +		pass + +	# Generate one sync-pulse +	def syncsignal(self): +		self.hilo ^= 1 +		return self.sync[self.hilo] + +	# Decode bits to modem signals +	def modemcode(self, byte): +		bleep = "" +		for x in xrange(8): +			self.hilo ^= 1 +			bleep += self.bits[self.hilo][byte & 0x01] +			byte >>= 1 +		return bleep + +	# Return <length> samples of silence +	def silence(self, length): +		return chr(127) * length + + +if len(sys.argv) < 2: +	print """Usage: {0} <input_filename> [output_wav_filename] [samplerate] + +	input_filename		Data file as input to modem. +	output_wav_filename	Write output-wav to this file. If empty, output to STDOUT. +	samplerate		Sample rate between 16000 - 48000. Default is 48000. +	""".format(sys.argv[0]) +	sys.exit() + +sound = "" + +m = modem() +cnt = 0 + +# Add silence +# sound += m.silence(24000) + +# Add 4 sync signals to start +for x in xrange(4): +	sound += m.syncsignal() + +# Send Actual data +f = open(sys.argv[1]) +for byte in f.read(): +	sound += m.modemcode(ord(byte)) + +	# Add counter +	cnt += 1 + +	# After every 10 bytes, send 2 sync signals +	if cnt == 10: +		for x in xrange(2): +			sound += m.syncsignal() +		cnt = 0 + +# End transmission with few sync-signals +for x in xrange(4): +	sound += m.syncsignal() + +# Output the generated sound (no wav headers) +if len(sys.argv) <= 2: +	print sound +else: +	freq = int(sys.argv[3]) if len(sys.argv) > 3 else 48000 +	wav = wave.open(sys.argv[2], 'wb') +	wav.setparams((1, 1, freq, 0, "NONE", None)) +	wav.writeframes(sound) +	wav.close() + | 
