Source

psk31 / psk.c

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

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

static uint8_t phase;


static void
output_bit(
	const 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];
			uint16_t u;

			// Default cosine = 1.0
			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 = cycle < 8
					? sin_table[32 + cycle * 4 + i / 32]
					: sin_table[96 - cycle * 4 - i / 32];
			}

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

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

			while ((TIFR1 & (1 << OCF1A)) == 0)
				;

			// Output this for 500 Hz / 128 clock ticks
			OCR1A += 250; // 16 MHz / 128 / 250 == 500 Hz
			TIFR1 |= 1 << OCF1A; // clear the OCF1A timer
		}
	}
}


static void output_word(uint16_t word)
{
	while (word)
	{
		uint8_t bit = word & 1;
		word >>= 1;

		output_bit(bit);
		//output_bit(TCNT1 & 1);
	}

	// 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
	OCR1A = TCNT1 + 10; // 16 MHz / 128 / 250 == 500 Hz

	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);
	}
}