psk31 / psk.c

/** \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;

// 833 Hz / 31.25 Hz == 27 cycles per bit
static const uint16_t bit_width = 27 * 128;


static void output_constant(void)
{
	for (uint16_t i = 0 ; i < bit_width ; i++)
	{
		const uint8_t s = sin_table[phase++ & 127];
		uint8_t spin = 32;
		while(spin--)
			PORTB = s;
	}
}


static void output_bit(unsigned bit)
{
	// 1 bits go out with no change in phase or amplitude
	if (bit)
	{
		output_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;
	}
}


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;

	// 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);
	}
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.