Source

psk31 / psk.c

Full commit
/** \file
 * Implement a PSK31 encoder.
 *
 * 8-bit output of 
 */
#include "WProgram.h"
#include "sin-table.h"
#include "varicode.h"

static const char msg[] = "ny3u KD4ISF QSO cq 0123456789\n";

static uint8_t phase;


static void
output_bit(
	uint8_t bit
)
{
	for (uint8_t cycle = 0 ; cycle < 16 ; cycle++)
	{
		// If we are outputting a zero, swap the phase
		if (cycle == 8 && bit == 0)
			phase += 64;

		for (uint8_t i = 0 ; i < 128 ; i++)
		{
			int16_t s = sin_table[(i + phase) & 127];
			int16_t c = 128;

			// if we are outputting a zero,
			// multiple the scale of this cycle
			// by the cosine of the cycle.
			if (bit == 0)
				c = sin_table[64 + cycle * 4 + i / 16];

			// Multiply by the cosine and add a DC offset
			// to get an unsigned value
			uint16_t u = (s * c) + 128 * 128;

			// Convert to an unsigned 5 bit value with dc offset
			PORTB = u >> 11;

			OCR1A += 250; // 16 MHz / 128 / 250 == 500 Hz
			TIFR1 |= 1 << OCF1A; // clear the OCF1A timer
			
			while ((TIFR1 & (1 << OCF1A)) == 0)
				;
		}
	}
}

#if 0
static void output_bit(unsigned bit)
{
	// 1 bits go out with no change in phase or amplitude
	if (1 || bit)
	{
		output_bit_constant();
		return;
	}

	// 0 bits ramp down to zero amplitude and then back up
	for (int16_t i = 0 ; i < 1024 ; i++)
	{
		int16_t s = (uint16_t) sin_table[phase++ & 127];
		// Shift it to the center of the waveform
		s -= 16;
		// scale it linearly
		s = (s * (1024 - i)) >> 10;
		// Shift it back to the DC offset
		s += 16;
		uint8_t spin = 28;
		while(spin--)
			PORTB = s;
	}
	
	// Shift the phase
	phase = (phase + 64) & 127;

	// And ramp up down to zero amplitude and then back up
	for (int16_t i = 0 ; i < 1024 ; i++)
	{
		int16_t s = (uint16_t) sin_table[phase++ & 127];
		// Shift it to the center of the waveform
		s -= 16;
		// scale it linearly
		s = (s * i) >> 10;
		// Shift it back to the DC offset
		s += 16;

		uint8_t spin = 28;
		while(spin--)
			PORTB = s;
	}

	// And now constant amplitude to round it out
	for (int16_t i = 0 ; i < bit_width - 1024 * 2 ; i++)
	{
		uint8_t s = sin_table[phase++ & 127];
		uint8_t spin = 32;
		while(spin--)
			PORTB = s;
	}
}
#endif


static void output_word(uint16_t word)
{
	while (word)
	{
		unsigned bit = word & 0x8000;
		word <<= 1;

		output_bit(bit);
	}

	// Mark the end ofthe word with two zeros
	output_bit(0);
	output_bit(0);
}

		
static void psk_main(void)
{
	// Port B has 6 bits of output on pins 8-13
	DDRB = 0x3F;

	// Timer1 at clk/1
	TCCR1B = 1;

	// Clock is 16 MHz
	// 512 Hz sine wave is 32768 instructions per cycle
	// 6 bits of output == 64 steps from 0 to 1
	// 128 steps in the sin table above
	// 32768 / 128 == 256 instructions per step

	uint8_t i = 0;
	while (1)
	{
		unsigned char c = msg[i++];
		if (c == '\0')
		{
			i = 0;
			continue;
		}

		uint16_t word = varicode[c];
		output_word(word);
	}
}