view testavr.c @ 63:4d914a1fd487

Fix printf typo from last commit. Cast away volatile to avoid compiler warning.
author darius@Inchoate
date Thu, 30 Oct 2008 20:09:32 +1030
parents 50fca9562310
children 1ef17cd8af7a
line wrap: on
line source

/*
 * Test various AVR bits and pieces
 *
 * Copyright (c) 2008
 *      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 <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/wdt.h>

#include "cons.h"
#include "1wire.h"
#ifdef WITHUSB
#include "usb.h"
#endif
#include "tempctrl.h"
#include "ds1307.h"

/*
 * Mirror of the MCUCSR register, taken early during startup.
 */
uint8_t mcucsr __attribute__((section(".noinit")));

void		process_cmd(void);

/*
 * Read out and reset MCUCSR early during startup.
 */
void handle_mcucsr(void)
    __attribute__((section(".init3")))
    __attribute__((naked));
void handle_mcucsr(void) {
    wdt_disable();
    mcucsr = MCUCSR;
    MCUCSR = 0;
}

int
main(void) {
    /* Disable interrupts while we frob stuff */
    cli();

#if 0
    /* Disable JTAG (yes twice) */
    MCUCSR |= _BV(JTD);
    MCUCSR |= _BV(JTD);
#endif

#ifdef WITHUSB
    /* USB data bus (7:0) */
    DDRA = 0x00;
    PORTA = 0x00;
    
    /* USB control (4:0) */
    DDRB = 0x0d;
    PORTB = 0x00;
#else
    DDRA = 0xff;
    PORTA = 0x00;

    DDRB = 0x00;
    PORTB = 0x00;

#endif    
    /* GPIO (0:7) */
    DDRC = 0xff;
    PORTC = 0x00;

    /* USART (0:1), IDBus (2:5), 485 (6:6), GPIO (7:7) */
    DDRD = 0xf7;
    PORTD = 0xf7;

#ifndef WITHUSB
    /* Beep
     *
     * Fpwm = Fclk / (N * 510)
     *      = 16e6 / (8 * 510)
     *      = 3921Hz
     *
     * Behind ifndef because PB3 is A0 on PDI chip
     *
     * Phase correct PWM, non-inverted output, divide by 8 */
    TCCR0 = _BV(WGM00) | _BV(WGM11) | _BV(COM00) | _BV(COM01) | _BV(CS01);
    OCR0 = 128;
#endif

    /* Set up the one wire stuff */
    OWInit();

    /* Setup IIC */
    ds1307_init();
    
    /* Init UART */
    cons_init();
    
    /* Init temperature control stuff */
    tempctrl_init();

    printf_P(PSTR("\r\n\r\n===============\r\n"
		  "Inited!\r\n\r\n"));

    if ((mcucsr & _BV(PORF)) == _BV(PORF))
	printf_P(PSTR("Power on reset\r\n"));

    if ((mcucsr & _BV(EXTRF)) == _BV(EXTRF))
	printf_P(PSTR("External reset\r\n"));

    if ((mcucsr & _BV(BORF)) == _BV(BORF))
	printf_P(PSTR("Brown-out reset\r\n"));

    if ((mcucsr & _BV(WDRF)) == _BV(WDRF))
	printf_P(PSTR("Watchdog reset\r\n"));

    if ((mcucsr & _BV(JTRF)) == _BV(JTRF))
	printf_P(PSTR("JTAG reset\r\n"));

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

    /*
     * Enable the watchdog with the largest prescaler.  Will cause a
     * watchdog reset after approximately 2 s @ Vcc = 5 V
     *
     * Gets reset in the loop below and in the tempctrl.c timer IRQ
     */
    wdt_enable(WDTO_2S);

#ifdef WITHUSB
    printf_P(PSTR("Calling usb_init\r\n"));
    usb_init();
    printf_P(PSTR("done\r\n"));
    _delay_us(1000);
#endif
    printf_P(PSTR("> "));
    cmd.state = 0;
    
    /* Wait for user input or an "interrupt" */
    while (1) {
	wdt_reset();

	tempctrl_update();
	
	if (cmd.state == 255) {
	    process_cmd();
	    printf_P(PSTR("> "));
	    /* Allow new characters to be processed */
	    cmd.state = 0;
	}
	
#ifdef WITHUSB
	if (!(PDICTL & _BV(PDIINT)))
	    usb_intr();
#endif
    }
}

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

    /* User just pressed enter */
    if (cmd.len == 0)
	return;
	     
    if (!strcasecmp_P((char *)cmd.buf, PSTR("?")) ||
	!strcasecmp_P((char *)cmd.buf, PSTR("help"))) {
        printf_P(PSTR("rs               Reset and check for presence\r\n"
		      "sr               Search the bus for ROMs\r\n"
		      "re               Read a bit\r\n"
		      "rb               Read a byte\r\n"
		      "wr bit           Write a bit\r\n"
		      "wb byte          Write a byte (hex)\r\n"
		      "wc cmd [ROMID]   Write command\r\n"
		      "te ROMID         Read the temperature from a DS1820\r\n"
		      "in port          Read from a port\r\n"
		      "ou port val      Write to a port (val in hex)\r\n"
		      "dd port [val]    Read/write DDR for a port (val in hex)\r\n"
		      "rt ROMID	        Read DS2502 status page\r\n"
		      "we ROMID adr val Write data into a DS2502 PROM (adr & val in hex)\r\n"
		      "rr ROMID         Read DS2502 PROM\r\n"
		      "zz		Reset MCU\r\n"
		      "gc               Get time of day\r\n"
		      "sc time          Set time of day (time is YYYY/MM/DD HH:MM:SS)\r\n"
#ifdef WITHUSB
		      "us               Generate USB data\r\n"
#endif
		      "tc ...           Temperature control related (tc help for more)\r\n"));
	
	return;
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("zz"), 2)) {
	cli();
	wdt_enable(WDTO_15MS);
	for (;;)
	    ;
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rs"), 2)) {
	printf_P(PSTR("Resetting... "));
	    
	if (OWTouchReset() == 1)
	    printf_P(PSTR("No presence pulse found\r\n"));
	else
	    printf_P(PSTR("Presence pulse found\r\n"));
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("re"), 2)) {
	if (OWReadBit())
	    printf_P(PSTR("Read a 1\r\n"));
	else
	    printf_P(PSTR("Read a 0\r\n"));
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rb"), 2)) {
	printf_P(PSTR("Read a 0x%02x\r\n"), OWReadByte());
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wr"), 2)) {
	arg = strtol((char *)cmd.buf + 3, (char **)NULL, 10);
	OWWriteBit(arg);
	printf_P(PSTR("Wrote a %c\r\n"), arg ? '1' : '0');
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wb"), 2)) {
	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); 
	OWWriteByte(arg);
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rt"), 2)) {
	if (sscanf_P((char *)cmd.buf, PSTR("rt %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), 
		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}
	
	if (ROM[0] != OW_FAMILY_ROM) {
	    printf_P(PSTR("ROM specified isn't a DS2502\r\n"));
	    return;
	}

	if (OWTouchReset() != 0) {
	    printf_P(PSTR("No presence\r\n"));
	    return;
	}
	
	crc = 0;

	OWCRC(OW_READ_STATUS, &crc);
	OWSendCmd(ROM, OW_READ_STATUS);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);
	
	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on command & address\r\n"));
	    return;
	}
	
	crc = 0;
	for (i = 0; i < 8; i++) {
	    temp = OWReadByte();
	    printf_P(PSTR("%02x "), temp);
	    OWCRC(temp, &crc);
	}
	printf_P(PSTR("\r\n"));
	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on data\r\n"));
	    return;
	}
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("we"), 2)) {
	uint8_t	adr, data;
	
	if (sscanf_P((char *)cmd.buf, PSTR("we %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhx %hhx"),
		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
		     &ROM[4], &ROM[5], &ROM[6], &ROM[7],
		     &adr, &data) != 10) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}

	if (ROM[0] != OW_FAMILY_ROM) {
	    printf_P(PSTR("ID specified isn't a ROM\r\n"));
	    return;
	}

	if (OWTouchReset() != 0) {
	    printf_P(PSTR("No presence\r\n"));
	    return;
	}

	printf_P(PSTR("OWProgROM returned %S\r\n"), OWProgROM_Status[OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0)]);
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rr"), 2)) {
	if (sscanf_P((char *)cmd.buf, PSTR("rr %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}

	if (ROM[0] != OW_FAMILY_ROM) {
	    printf_P(PSTR("ROM specified isn't a ROM\r\n"));
	    return;
	}

	crc = 0;
	OWSendCmd(ROM, OW_READ_MEMORY);
	OWCRC(OW_READ_MEMORY, &crc);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);

	OWWriteByte(0x00);
	OWCRC(0x00, &crc);

	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on command & address\r\n"));
	    return;
	}

	crc = 0;
	for (buf[0] = 0; buf[0] < 128; buf[0]++) {
	    buf[1] = OWReadByte();
	    if (buf[0] > 0) {
		if (buf[0] % 16 != 0)
		    printf_P(PSTR(" "));
		else
		    printf_P(PSTR("\r\n"));
	    }
	    
	    printf_P(PSTR("%02x"), buf[1]);
	    OWCRC(buf[1], &crc);
	}
	printf_P(PSTR("\r\n"));
	if (crc != OWReadByte()) {
	    printf_P(PSTR("CRC mismatch on data\r\n"));
	    return;
	}
	
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wc"), 2)) {
	uint8_t c;
	
	i = sscanf_P((char *)cmd.buf, PSTR("wc %hhx %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
		     &ROM[4], &ROM[5], &ROM[6], &ROM[7],
		     &c);
	
	if (i != 1 && i != 9) {
	    printf_P(PSTR("Incorrect usage\r\n"));
	    return;
	}
	    
	if (i == 1) {
	    OWSendCmd(i == 1 ? NULL : ROM, c);
	    return;
	}
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("te"), 2)) {
	if (sscanf_P((char *)cmd.buf, PSTR("te %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), 
		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
	    return;
	}

	t = OWGetTemp(ROM);
	switch (t) {
	    case OW_TEMP_WRONG_FAM:
		printf_P(PSTR("ROM specified isn't a temperature sensor\r\n"));
		break;

	    case OW_TEMP_CRC_ERR:
		printf_P(PSTR("CRC mismatch\r\n"));
		break;

	    case OW_TEMP_NO_ROM:
		printf_P(PSTR("No ROM found\r\n"));
		break;

	    default:
		printf_P(PSTR("%d.%02d\r\n"), GETWHOLE(t), GETFRAC(t));
		break;
	}
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sr"), 2)) {
	memset(ROM, 0, 8);

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

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

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

	    for (i = 0; i < 8; i++)
		printf_P(PSTR("%02x%S"), ROM[i], i == 7 ? PSTR("\r\n") : PSTR(":"));

	    i = OWNext(ROM, 1, 0);
	} while (1);
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("in"), 2)) {
	uint8_t inp;
	    
	switch (tolower(cmd.buf[3])) {
	    case 'a':
		inp = PINA;
		break;
		
	    case 'b':
		inp = PINB;
		break;
		
	    case 'c':
		inp = PINC;
		break;
		
	    case 'd':
		inp = PIND;
		break;
		
	    default:
		printf_P(PSTR("Unknown port\r\n"));
		return;
	}
	printf_P(PSTR("0x%02x\r\n"), inp);
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("ou"), 2)) {
	char port;
	int val;
	
	if (sscanf_P((char *)cmd.buf, PSTR("ou %c %x"), &port, &val) != 2) {
	    printf_P(PSTR("Unable to parse ou arguments\r\n"));
	    return;
	}
	
	switch (port) {
	    case 'a':
		PORTA = val & 0xff;
		break;
		
	    case 'b':
		PORTB = val & 0xff;
		break;
		
	    case 'c':
		PORTC = val & 0xff;
		break;
		
	    case 'd':
		PORTD = val & 0xff;
		break;
		
	    default:
		printf_P(PSTR("Unknown port\r\n"));
		return;
	}
	printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(port), val);
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("dd"), 2)) {
	char port;
	uint8_t val;
	int num;
	
	num = sscanf_P((char *)cmd.buf, PSTR("dd %c %x"), &port, &val);
	
	if (num != 2 && num != 3) {
	    printf_P(PSTR("Unable to parse dd arguments\r\n"));
	    return;
	}
	
	if (num == 2) {
	    switch (port) {
		case 'a':
		    val = DDRA;
		    break;

		case 'b':
		    val = DDRB;
		    break;

		case 'c':
		    val = DDRC;
		    break;
		    
		case 'd':
		    val = DDRD;
		    break;
		
		default:
		    printf_P(PSTR("Unknown port\r\n"));
		    return;
	    }
	    printf_P(PSTR("DDR%c => 0x%02x\r\n"), toupper(port), val);
	} else {
	    switch (port) {
		case 'a':
		    DDRA = val & 0xff;
		    break;
		
		case 'b':
		    DDRB = val & 0xff;
		    break;
		
		case 'c':
		    DDRC = val & 0xff;
		    break;
		
		case 'd':
		    DDRD = val & 0xff;
		    break;
		
		default:
		    printf_P(PSTR("Unknown port\r\n"));
		    return;
	    }
	    printf_P(PSTR("DDR%c <= 0x%02x\r\n"), toupper(port), val);
	}
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("tc"), 2)) {
	tempctrl_cmd((char *)cmd.buf);
#ifdef WITHUSB
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("us"), 2)) {
	usb_gendata();
#endif
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("gc"), 2)) {
	ds1307_printtime(PSTR(""), PSTR("\r\n"));
    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sc"), 2)) {
	if (cmd.len < 17) {
	    printf_P(PSTR("Command not long enough\r\n"));
	} else {
	    if (ds1307_settod((char *)cmd.buf + 3) != 1)
		printf_P(PSTR("Unable to set time of day\r\n"));
	}
    } else {
	printf_P(PSTR("Unknown command, help for a list\r\n"));
    }
}