Source

teletype / asr33.c

Full commit
/**
 * \file 110 current loop interface for an ASR33
 */

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <string.h>
#include <util/delay.h>
#include "usb_serial.h"
#include "bits.h"


// Send a string to the USB serial port.  The string must be in
// flash memory, using PSTR
//
void send_str(const char *s)
{
	char c;
	while (1) {
		c = pgm_read_byte(s++);
		if (!c) break;
		usb_serial_putchar(c);
	}
}


static char
hexdigit(
	uint8_t x
)
{
	x &= 0xF;
	if (x < 0xA)
		return x + '0';
	else
		return x + 'A' - 0xA;
}

//#define TTY_RX 0xD2
#define TTY_RX 0xF7
#define TTY_TX 0xD3
#define BIT_CLOCK 9090


static void
tty_out(
	uint8_t c
)
{
	// start bit
	out(TTY_TX, 1);

	_delay_us(BIT_CLOCK);
	uint8_t parity = 1;

	for (int i = 0 ; i < 7 ; i++)
	{
		int x = c & 1;
		c >>= 1;

		if (x)
		{
			out(TTY_TX, 0);
			parity++;
		} else {
			out(TTY_TX, 1);
		}

		_delay_us(BIT_CLOCK);
	}

	out(TTY_TX, parity);
	_delay_us(BIT_CLOCK);

	out(TTY_TX, 0);
	_delay_us(BIT_CLOCK);
	_delay_us(BIT_CLOCK);
}


/**
 * Enable ADC and select input ADC7 / F7
 * Select high-speed mode, left aligned
 * Use clock divisor of 2
 * System clock is 16 MHz on teensy, 8 MHz on tiny,
 * conversions take 13 ticks, so divisor == 128 (1,1,1) should
 * give 9.6 KHz of samples.
 */
static void
adc_init(void)
{
	ADMUX = 0
		| 7
		| (0 << REFS1)
		| (1 << REFS0)
		;

	ADCSRA = 0
		| (1 << ADEN) // enable ADC
		| (0 << ADSC) // don't start yet
		| (0 << ADIE) // don't enable the interrupts
		| (0 << ADPS2)
		| (1 << ADPS1)
		| (1 << ADPS0)
		;

	ADCSRB = 0
		| (1 << ADHSM) // enable highspeed mode
		;

	DDRF = 0;

	// Start the first conversion!
	sbi(ADCSRA, ADSC);
}


static uint16_t
adc_read_block(void)
{
	// Wait for the conversion to complete
	while (bit_is_set(ADCSRA, ADSC))
		continue;

	const uint16_t value = ADC;

	// Start the next conversion
	sbi(ADCSRA, ADSC);

	// Read the value
	return value;
}



static uint16_t
tty_in(void)
{
	uint16_t byte = 0;

#undef CONFIG_WAVEFORM
#ifndef CONFIG_WAVEFORM
	// 1 start bit, 7 data, 1 parity, 2 stop bits
#define NUM_BITS (1 + 7 + 1 + 2)

	for (int bit = 0 ; bit < NUM_BITS ; bit++)
	{
		if (bit == 0)
			_delay_us(BIT_CLOCK/4*3);
		else
			_delay_us(BIT_CLOCK);

		if (in(TTY_RX))
			byte = (byte >> 1) | (((uint16_t) 1) << NUM_BITS);
		else
			byte >>= 1;
	}
#else
#define TTY_BITS 64
	char buf[TTY_BITS];
	adc_read_block();

	for (int bit = 0 ; bit < TTY_BITS ; bit++)
	{
		//int x = in(TTY_RX);
		//buf[bit] = x ? '0' : '1';
		int x = adc_read_block();
		buf[bit] = hexdigit(x >> 6);
		_delay_us(BIT_CLOCK/4);
// 220000BB9045608B7000078B79AB9000099DA8BBADCC998A9A9AAAAABBCBBBBB
// 22 0000 BB90 4560 8B70 0007 8B79 AB90 0009 9DA8 BBAD CC99 8A9A 9AAAAABBCBBBBB
	}
	usb_serial_write(buf, sizeof(buf));
#endif

	return byte;
}


int main(void)
{
	// set for 16 MHz clock
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
	CPU_PRESCALE(0);

	// Disable the ADC
	ADMUX = 0;
	adc_init();

	ddr(TTY_TX, 1);
	out(TTY_TX, 0); // pull low against resistor

	// D2 is used for input (since it is also a UART)
	// it has an external pull up resistor to +5v
	ddr(TTY_RX, 0);
	out(TTY_RX, 0);

#if 0
	// 110 E72 is too SLOW at 16 MHz.  Wow.
	// bit banging it is...
	UBRR0 = ;
	UCSR0B = (1 << RXEN0);
	UCSR0C = 0
		| (1 << UPM11) // even parity
		| (0 << UPM10)
		| (0 << UCSZ12) // 7 data bits
		| (1 << UCSZ11)
		| (0 << UCSZ10)
		| (1 << USBS1) // 2 stop bits
		;
#endif

	// initialize the USB, and then wait for the host
	// to set configuration.  If the Teensy is powered
	// without a PC connected to the USB port, this 
	// will wait forever.
	usb_init();
	while (!usb_configured())
		continue;

	_delay_ms(500);

	// wait for the user to run their terminal emulator program
	// which sets DTR to indicate it is ready to receive.
	while (!(usb_serial_get_control() & USB_SERIAL_DTR))
		continue;

	// discard anything that was received prior.  Sometimes the
	// operating system or other software will send a modem
	// "AT command", which can still be buffered.
	usb_serial_flush_input();

	ddr(0xD6, 1); // LED

	int status = 0;

	while (1)
	{
		int c = usb_serial_getchar();
		if (c != -1)
		{
			out(0xD6, 1);
			tty_out(c);
			out(0xD6, 0);
		}

		int x = in(TTY_RX);

		// Wait for start bit
		if (x)
			continue;

		uint16_t byte = tty_in();
#ifndef CONFIG_WAVEFORM
		usb_serial_putchar(hexdigit(byte >> 12));
		usb_serial_putchar(hexdigit(byte >> 8));
		usb_serial_putchar(hexdigit(byte >> 4));
		usb_serial_putchar(hexdigit(byte >> 0));
		usb_serial_putchar(' ');
		usb_serial_putchar((byte >> 2) & 0x7F);
#endif
		usb_serial_putchar('\r');
		usb_serial_putchar('\n');
		continue;

	}
}