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 char msg[] = "ny3u KD4ISF QSO cq 0123456789\n";

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;

			// if we are outputting a zero,
			// multiple the scale of this cycle
			// by the cosine of the cycle.
			if (bit == 0)
			{
				int16_t 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;
			} else {
				// Just output it straight
				u = (s + 128) * 128;
			}

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

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


static void output_word(uint16_t word)
{
	while (word)
	{
		uint8_t bit = (word & 0x8000) ? 1 : 0;
		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

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