Source

alphawatch / alphawatch.c

Full commit
Trammell Hudson 521c6b2 
Trammell Hudson 8f95de1 


Trammell Hudson 521c6b2 















































Trammell Hudson 4e091db 

Trammell Hudson 521c6b2 
Trammell Hudson 94a2e4c 




Trammell Hudson 521c6b2 
Trammell Hudson 94a2e4c 







Trammell Hudson 521c6b2 
Trammell Hudson 94a2e4c 




Trammell Hudson 521c6b2 
Trammell Hudson f3213a8 
Trammell Hudson 4e091db 
Trammell Hudson f3213a8 











Trammell Hudson 4e091db 
Trammell Hudson f3213a8 















Trammell Hudson 4e091db 
Trammell Hudson f3213a8 
Trammell Hudson 521c6b2 


Trammell Hudson 8f95de1 



Trammell Hudson 521c6b2 
Trammell Hudson 8f95de1 















Trammell Hudson 94a2e4c 
Trammell Hudson 8f95de1 
Trammell Hudson 94a2e4c 
Trammell Hudson 521c6b2 

Trammell Hudson 4e091db 



Trammell Hudson f3213a8 
Trammell Hudson 4e091db 


































































































Trammell Hudson f3213a8 
Trammell Hudson 521c6b2 



















Trammell Hudson 8f95de1 














Trammell Hudson 94a2e4c 












Trammell Hudson 8f95de1 

Trammell Hudson 94a2e4c 
Trammell Hudson 8f95de1 








Trammell Hudson 4e091db 






Trammell Hudson 521c6b2 


































Trammell Hudson 8f95de1 
Trammell Hudson 4e091db 

Trammell Hudson f3213a8 
Trammell Hudson 521c6b2 




Trammell Hudson 8f95de1 
Trammell Hudson 4e091db 








Trammell Hudson 521c6b2 

Trammell Hudson 4e091db 
















Trammell Hudson 521c6b2 
Trammell Hudson 4e091db 

Trammell Hudson 521c6b2 

/**
 * \file Alpha numeric watch
 *
 * Based on the HDSP-2110 display.
 *
 */

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


#define LED			0xD6


void send_str(const char *s);
uint8_t recv_str(char *buf, uint8_t size);
void parse_and_execute_command(const char *buf, uint8_t num);

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



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

#define CHAR_RAM 0x18


#define ADDR_0	0xF4
#define ADDR_1	0xF5
#define ADDR_2	0xF6
#define ADDR_3	0xF7
#define ADDR_4	0xD7

#define DATA_0	0xC6
#define DATA_1	0xD3
#define DATA_2	0xD0
#define DATA_3	0xB7
#define DATA_4	0xB3
#define DATA_5	0xB2
#define DATA_6	0xB1
#define DATA_7	0xB0

#define FLASH	0xF1
#define RESET	0xF0
#define WRCE	0xD5
#define RD	0xC7
#define CLKSEL	0xD6

static const char numbers[][16] = {
	"",
	"one",
	"two",
	"three",
	"four",
	"five",
	"six",
	"seven",
	"eight",
	"nine",
	"ten",
	"eleven",
	"twelve",
	"thirteen",
	"fourteen",
	"fifteen",
	"sixteen",
	"seventeen",
	"eightteen",
	"nineteen",
	"twenty",
	"twenty one",
	"twenty two",
	"twenty three",
	"twenty four",
	"twenty five",
	"twenty six",
	"twenty seven",
	"twenty eight",
	"twenty nine",
	"half",
};


static void
lcd_write(
	uint8_t addr,
	uint8_t data
)
{
	out(ADDR_0, addr & 1); addr >>= 1;
	out(ADDR_1, addr & 1); addr >>= 1;
	out(ADDR_2, addr & 1); addr >>= 1;
	out(ADDR_3, addr & 1); addr >>= 1;
	out(ADDR_4, addr & 1); addr >>= 1;

	out(DATA_0, data & 1); data >>= 1;
	out(DATA_1, data & 1); data >>= 1;
	out(DATA_2, data & 1); data >>= 1;
	out(DATA_3, data & 1); data >>= 1;
	out(DATA_4, data & 1); data >>= 1;
	out(DATA_5, data & 1); data >>= 1;
	out(DATA_6, data & 1); data >>= 1;
	out(DATA_7, data & 1); data >>= 1;

	//_delay_us(100);
	out(WRCE, 0);
	_delay_us(10);
	out(WRCE, 1);
}

static uint8_t ms;
static uint8_t sec;
static uint8_t min;
static uint8_t hour;

static void
update_time(void)
{
	if (++ms < 200)
		return;

	ms = 0;
	if (++sec< 60)
		return;

	sec = 0;
	if (++min < 60)
		return;

	min = 0;
	if (++hour < 24)
		return;

	hour = 0;
}


static char scroll_output[64];
static uint8_t scroll_offset;

static void
scroll(void)
{
	uint8_t did_reset = 0;

	for (int i = 0 ; i < 8 ; i++)
	{
		char c = scroll_output[scroll_offset+i];
		if (did_reset || c == '\0')
		{
			did_reset = 1;
			c = ' ';
		}
	
		lcd_write(CHAR_RAM + i, c);
	}

	if (did_reset)
		scroll_offset = 0;
	else
		scroll_offset++;
}


static void
draw_hms(void)
{
	lcd_write(CHAR_RAM | 0, '0' + (hour / 10) % 10);
	lcd_write(CHAR_RAM | 1, '0' + (hour / 1) % 10);
	lcd_write(CHAR_RAM | 2, ':');
	lcd_write(CHAR_RAM | 3, '0' + (min / 10) % 10);
	lcd_write(CHAR_RAM | 4, '0' + (min / 1) % 10);
	lcd_write(CHAR_RAM | 5, ':');
	lcd_write(CHAR_RAM | 6, '0' + (sec / 10) % 10);
	lcd_write(CHAR_RAM | 7, '0' + (sec / 1) % 10);
}


static void
word_clock(void)
{
	scroll_output[0] = '\0';
	strcat(scroll_output, "       ");

	if (min <= 30)
	{
		if (min != 0)
		{
			strcat(scroll_output, numbers[min]);
			strcat(scroll_output, " past ");
		}

		if (hour == 12)
			strcat(scroll_output, "noon");
		else
		if (hour == 0)
			strcat(scroll_output, "midnight");
		else
			strcat(scroll_output, numbers[hour]);
	} else {
		strcat(scroll_output, numbers[60-min]);
		strcat(scroll_output, " before ");
		if (hour == 11)
			strcat(scroll_output, "noon");
		else
		if (hour == 23)
			strcat(scroll_output, "midnight");
		else
			strcat(scroll_output, numbers[hour+1]);
	}

	strcat(scroll_output, "      ");
}


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

	// Disable the ADC
	ADMUX = 0;

	// 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();

	// LED is an output; will be pulled down once connected
	ddr(LED, 1);
	out(LED, 1);

	ddr(DATA_0, 1);
	ddr(DATA_1, 1);
	ddr(DATA_2, 1);
	ddr(DATA_3, 1);
	ddr(DATA_4, 1);
	ddr(DATA_5, 1);
	ddr(DATA_6, 1);
	ddr(DATA_7, 1);

	ddr(ADDR_0, 1);
	ddr(ADDR_1, 1);
	ddr(ADDR_2, 1);
	ddr(ADDR_3, 1);
	ddr(ADDR_4, 1);

	// !FLASH should be high to select normal memory
	out(FLASH, 1);
	ddr(FLASH, 1);

	// CLS should be high to select internal clocks
	out(CLKSEL, 1);
	ddr(CLKSEL, 1);

	// WRCE ties together !WR and !CE
	out(WRCE, 1);
	ddr(WRCE, 1);

	out(RESET, 1);
	ddr(RESET, 1);

	// Reset the display
	_delay_ms(100);
	out(RESET, 0);
	_delay_ms(10);
	out(RESET, 1);

	// We should be good to go
	lcd_write(0x20, 0x00); // normal operation

	lcd_write(CHAR_RAM | 0, 'A');
	lcd_write(CHAR_RAM | 1, 'l');
	lcd_write(CHAR_RAM | 2, 'p');
	lcd_write(CHAR_RAM | 3, 'h');
	lcd_write(CHAR_RAM | 4, 'a');
	lcd_write(CHAR_RAM | 5, 'C');
	lcd_write(CHAR_RAM | 6, 'L');
	lcd_write(CHAR_RAM | 7, 'K');

        // Timer 0 is used for a 64 Hz control loop timer.
        // Clk/1024 == 15.625 KHz, count up to 244
        // CTC mode resets the counter when it hits the top
        TCCR0A = 0
                | 1 << WGM01 // select CTC
                | 0 << WGM00
                ;

        TCCR0B = 0
                | 0 << WGM02
                | 1 << CS02 // select Clk/1024
                | 0 << CS01
                | 0 << CS00
                ;

        OCR0A = 244;
        sbi(TIFR0, OCF0A); // reset the overflow bit


	while (!usb_configured())
		;

	_delay_ms(1000);

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

	// 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();

	send_str(PSTR("alphawatch\r\n"));
	char line[16];
	uint8_t line_offset = 0;

	while (1)
	{
		int c = usb_serial_getchar();
		if (c != -1)
		{
			usb_serial_putchar(c);
			if (c == '\r')
			{
				hour = (line[0] - '0') * 10 + (line[1] - '0');
				min = (line[2] - '0') * 10 + (line[3] - '0');
				sec = (line[4] - '0') * 10 + (line[5] - '0');
				line_offset = 0;
			} else {
				line[line_offset++] = c;
			}
		}

		if (bit_is_clear(TIFR0, OCF0A))
			continue;
		sbi(TIFR0, OCF0A); // reset the bit

		update_time();

		static uint8_t rate = 0;
		if ((rate++) < 40)
			continue;
		rate = 0;

		const uint8_t mode = 1;

		if (mode == 0)
			draw_hms();
		else
		if (mode == 1)
		{
			word_clock();
			scroll();
		}
	}
}