view testavr.c @ 35:fed32b382de2

Tidy up, hide details behind macros to make it more obvious what we talk to do do things. Convert constants to my preferred format.
author darius
date Tue, 23 Oct 2007 10:54:01 +0930
parents 48056516b3eb
children 25fa387ef7e9
line wrap: on
line source

/*
 * Test various AVR bits and pieces
 *
 * $Id$
 *
 * Copyright (c) 2004
 *      Daniel O'Connor <darius@dons.net.au>.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <util/delay.h>

#include "1wire.h"
#include "usb.h"

#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1)
#define UART_BAUD_RATE		38400

void		process_cmd(void);

void		uart_putsP(const char *addr);
void		uart_puts(const char *addr);
int		uart_putc(char c);
void		uart_puts_dec(uint8_t a, uint8_t l);
void		uart_puts_hex(uint8_t a);
char		uart_getc(void);

/* Receive buffer storage */
volatile struct {
    char	buf[40];
    uint8_t	state;
    uint8_t	len;
} cmd = {
    .state = 255,
    .len = 0
};

/* Rx complete */
ISR(USART_RXC_vect) {
    volatile char pit;
    char c;
    
    while (UCSRA & _BV(RXC)) {
	/* 255 means we're waiting for main to process the command,
	   just throw stuff away
	*/
	if (cmd.state == 255) {
	    pit = UDR;
	    continue;
	}
	c = UDR;
	
	/* End of line? */
	if (c == '\n' || c == '\r') {
	    cmd.buf[cmd.state + 1] = '\0';
	    uart_putsP(PSTR("\n\r"));
	    cmd.len = cmd.state;
	    cmd.state = 255;
	    continue;
	}
	
	/* Backspace/delete */
	if (c == 0x08 || c == 0x7f) {
	    if (cmd.state > 0) {
		cmd.state--;
		uart_putsP(PSTR("\010\040\010"));
	    }
	    continue;
	}
	
	/* Anything unprintable just ignore it */
	if (!isprint(c))
	    continue;

	cmd.buf[cmd.state] = tolower(c);

	/* Echo back to the user */
	uart_putc(cmd.buf[cmd.state]);
	
	cmd.state++;
	/* Over flow? */
	if (cmd.state == ((sizeof(cmd.buf) / sizeof(cmd.buf[0])) - 1)) {
	    uart_putsP(PSTR("\n\rLine too long"));
	    cmd.state = 0;
	    continue;
	}
    }
}

/* Tx complete */
ISR(USART_TXC_vect) {
	
}
    
int
main(void) {
    /* Disable interrupts while we frob stuff */
    cli();

    /* Disable JTAG (yes twice) */
    MCUCSR |= _BV(JTD);
    MCUCSR |= _BV(JTD);
    
    /* USB data bus (7:0) */
    DDRA = 0x00;
    PORTA = 0x00;
    
    /* USB control (3:0) */
    DDRB = 0x0e;
    PORTB = 0x00;
    
    /* GPIO (0:7) */
    DDRC = 0xff;
    PORTC = 0x00;

    /* GPIO (2:7) */
    DDRD = 0xfc;
    PORTD = 0xfc;

    /* Init UART */
    UBRRH = UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) >> 8;
    UBRRL = (uint8_t)UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU);
    
    /* Enable receiver and transmitter. Turn on transmit interrupts */
    UCSRA = 0;
    UCSRB = _BV(RXEN) | _BV(TXEN) | _BV(RXCIE);
    UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);
    uart_putsP(PSTR("\n\r\n\r===============\n\r"
		    "Inited!\n\r\n\r"));

    /* Ready to go! */
    sei();

    usb_init();
    _delay_us(1000);
    
    uart_putsP(PSTR("> "));
    cmd.state = 0;
    
    /* Wait for user input or an "interrupt" */
    while (1) {
	if (cmd.state == 255) {
	    process_cmd();
	    uart_putsP(PSTR("> "));
	    /* Allow new characters to be processed */
	    cmd.state = 0;
	}
	
	if (!(PINB & _BV(PB0)))
	    usb_intr();
    }
}

void
process_cmd(void) {
    uint8_t	ROM[8];
    int8_t	i, arg;
    uint8_t	crc, buf[9];
    int8_t	temp;
    uint16_t	tfrac;

    /* User just pressed enter */
    if (cmd.len == 0)
	return;
	     
    if (cmd.buf[0] == '?') {
        uart_putsP(PSTR("rs               Reset and check for presence\n\r"
                        "sr               Search the bus for ROMs\n\r"
                        "re               Read a bit\n\r"
                        "rb               Read a byte\n\r"
                        "wr  bit          Write a bit\n\r"
                        "wb  byte         Write a byte (hex)\n\r"
                        "wc  cmd [ROMID]  Write command\n\r"
                        "te  ROMID        Read the temperature from a DS1820\n\r"
                        "in  port         Read from a port\n\r"
                        "out port val     Write to a port\n\r"
                        "ddr port [val]   Read/write DDR for a port\n\r"));
	    
	return;
    }
	
    i = strlen((char *)cmd.buf);
    if (cmd.len < 2)
	goto badcmd;
	
    if (cmd.buf[0] == 'r' && cmd.buf[1] == 's') {
	uart_putsP(PSTR("Resetting... "));
	    
	if (OWTouchReset() == 1)
	    uart_putsP(PSTR("No presence pulse found\n\r"));
	else
	    uart_putsP(PSTR("Presence pulse found\n\r"));
    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'e') {
	if (OWReadBit())
	    uart_putsP(PSTR("Read a 1\n\r"));
	else
	    uart_putsP(PSTR("Read a 0\n\r"));
    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'b') {
	uart_putsP(PSTR("Read a 0x"));
	uart_puts_hex(OWReadByte());
	uart_putsP(PSTR("\n\r"));
    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'r') {
	arg = strtol((char *)cmd.buf + 3, (char **)NULL, 10);
	OWWriteBit(arg);
	uart_putsP(PSTR("Wrote a "));
	if (arg)
	    uart_putsP(PSTR("1\n\r"));
	else
	    uart_putsP(PSTR("0\n\r"));
    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'b') {
	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); 
	OWWriteByte(arg);
    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'c') {
	if (cmd.len < 5) {
	    uart_putsP(PSTR("No arguments\n\r"));
	    return;
	}
	    
	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16);
	if (arg == 0) {
	    uart_putsP(PSTR("Unparseable command\n\r"));
	    return;
	}

	if (i == 5) {
	    OWSendCmd(NULL, arg);
	    return;
	}
	    
	if (i < 29) {
	    uart_putsP(PSTR("Can't parse ROM ID\n\r"));
	    return;
	}
	for (i = 0; i < 8; i++)
	    ROM[i] = (int)strtol((char *)cmd.buf + 6 + (3 * i), (char **)NULL, 16);

	OWSendCmd(ROM, arg);
    } else if (cmd.buf[0] == 't' && cmd.buf[1] == 'e') {
	if (cmd.len < 26) {
	    uart_putsP(PSTR("Unable to parse ROM ID\n\r"));
	    return;
	}

	for (i = 0; i < 8; i++)
	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);

	if (ROM[0] != OW_FAMILY_TEMP) {
	    uart_putsP(PSTR("ROM specified isn't a temperature sensor\n\r"));
	    return;
	}
	    
	OWSendCmd(ROM, OW_CONVERTT_CMD);
	i = 0;
	while (OWReadBit() == 0) {
	    i++;
	}
	OWSendCmd(ROM, OW_RD_SCR_CMD);
	crc = 0;
	for (i = 0; i < 9; i++) {
	    buf[i] = OWReadByte();
	    if (i < 8)
		OWCRC(buf[i], &crc);
	}
	    
	if (crc != buf[8]) {
	    uart_putsP(PSTR("CRC mismatch\n\r"));
	    return;
	}
	    
#if 0
	uart_putsP(PSTR("temperature "));
	uart_puts_dec(temp >> 4, 0);
	uart_putsP(PSTR("."));
	uart_puts_dec((temp << 12) / 6553, 0);
	uart_putsP(PSTR("\n\r"));
#else
	/* 0	Temperature LSB
	 * 1	Temperature MSB
	 * 2	Th
	 * 3	Tl
	 * 4	Reserved
	 * 5	Reserved
	 * 6	Count Remain
	 * 7	Count per C
	 * 8	CRC
	 */
#if 0
	for (i = 0; i < 9; i++) {
	    uart_puts_dec(buf[i], 0);
	    uart_putsP(PSTR("\n\r"));
	}
#endif
	temp = buf[0];
	if (buf[1] & 0x80)
	    temp -= 256;
	temp >>= 1;

	tfrac = buf[7] - buf[6];
	tfrac *= (uint16_t)100;
	tfrac /= buf[7];
	tfrac += 75;
	if (tfrac < 100) {
	    temp--;
	} else {
	    tfrac -= 100;
	}
	    
	if (temp < 0){
	    uart_putc('-');
	    uart_puts_dec(-temp, 0);
	} else
	    uart_puts_dec(temp, 0);
	uart_putsP(PSTR("."));
	uart_puts_dec(tfrac, 1);
	uart_putsP(PSTR("\n\r"));
	    
#endif
    } else if (cmd.buf[0] == 's' && cmd.buf[1] == 'r') {
	memset(ROM, 0, 8);

	i = OWFirst(ROM, 1, 0);
	do {
	    switch (i) {
		case OW_BADWIRE:
		    uart_putsP(PSTR("Presence pulse, but no module found, bad module/cabling?\n\r"));
		    break;

		case OW_NOPRESENCE:
		    uart_putsP(PSTR("No presence pulse found\n\r"));
		    break;
		    
		case OW_BADCRC:
		    uart_putsP(PSTR("Bad CRC\n\r"));
		    break;

		case OW_NOMODULES:
		case OW_FOUND:
		    break;
		    
		default:
		    uart_putsP(PSTR("Unknown error from 1 wire library\n\r"));
		    break;
	    }
		
	    if (i != OW_FOUND)
		break;

	    for (i = 0; i < 7; i++) {
		uart_puts_hex(ROM[i]);
		uart_putc(':');
	    }
	    uart_puts_hex(ROM[7]);
	    uart_putsP(PSTR("\n\r"));

	    i = OWNext(ROM, 1, 0);
	} while (1);
    } else if (cmd.buf[0] == 'i' && cmd.buf[1] == 'n') {
	switch (tolower(cmd.buf[3])) {
	    case 'a':
		crc = PINA;
		break;
		
	    case 'b':
		crc = PINB;
		break;
		
	    case 'c':
		crc = PINC;
		break;
		
	    case 'd':
		crc = PIND;
		break;
		
	    default:
		uart_putsP(PSTR("Unknown port\n\r"));
		return;
	}
	uart_putsP(PSTR("0x"));
	uart_puts_hex(crc);
	uart_putsP(PSTR("\n\r"));
    } else if (cmd.buf[0] == 'o' && cmd.buf[1] == 'u') {
	crc = strtol((char *)cmd.buf + 8, (char **)NULL, 16);
	switch (tolower(cmd.buf[4])) {
	    case 'a':
		PORTA = crc;
		break;
		
	    case 'b':
		PORTB = crc;
		break;
		
	    case 'c':
		PORTC = crc;
		break;
		
	    case 'd':
		PORTD = crc;
		break;
		
	    default:
		uart_putsP(PSTR("Unknown port\n\r"));
		return;
	}
	uart_putsP(PSTR("0x"));
	uart_puts_hex(crc);
	uart_putsP(PSTR("\n\r")); 
    } else if (cmd.buf[0] == 'u' && cmd.buf[1] == 's') {
	usb_gendata();
    } else {
      badcmd:
	uart_putsP(PSTR("Unknown command, ? for a list\n\r"));
    }
}
    
int
uart_putc(char c) {
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = c;

    return(0);
}

void
uart_putsP(const char *addr) {
    char c;

    while ((c = pgm_read_byte_near(addr++)))
	uart_putc(c);
}

void
uart_puts(const char *addr) {
    while (*addr)
	uart_putc(*addr++);
}

void
uart_puts_dec(uint8_t a, uint8_t l) {
    char	s[4];
    
    if (l && a < 10)
	uart_putsP(PSTR("0"));
    uart_puts(utoa(a, s, 10));
}

void
uart_puts_hex(uint8_t a) {
    char	s[3];
    
    if (a < 0x10)
	uart_putc('0');
    
    uart_puts(utoa(a, s, 16));
}

char
uart_getc(void) {
    while (!(UCSRA & _BV(RXC)))
	;
    
    return (UDR);
}