Mercurial > ~darius > hgwebdir.cgi > tempctrl
changeset 41:5898fba6593c
Add temperature control.
- Split out console stuff to cons.[ch]. Set up stdio so we can use printf etc.
- Use \r\n as the line terminator consistently.
- Add OWGetTemp to get temperatures from a device.
- Load/save settings in EEPROM, defaults loaded from flash.
Nearly feature complete except you can't edit ROM IDs without a programming tool :)
(To be fixed)
Needs more testing.
author | darius@inchoate.localdomain |
---|---|
date | Sun, 06 Jul 2008 22:19:53 +0930 |
parents | 1061fdbdc44f |
children | 97ae82023d5b |
files | 1wire-config.h 1wire.c 1wire.h Makefile cons.c cons.h tempctrl.c tempctrl.h testavr.c usb.c |
diffstat | 10 files changed, 1025 insertions(+), 323 deletions(-) [+] |
line wrap: on
line diff
--- a/1wire-config.h Thu Nov 22 16:02:40 2007 +0000 +++ b/1wire-config.h Sun Jul 06 22:19:53 2008 +0930 @@ -76,20 +76,13 @@ _delay_us(48);_delay_us(48); _delay_us(48); } while (0) /* 480 usec */ #define OWDELAY_I do { _delay_us(48); _delay_us(22); } while (0) /* 70 usec */ -void uart_putsP(const char *addr); -void uart_puts(const char *addr); -void uart_puts_hex(uint8_t a); -void uart_puts_dec(uint8_t a, uint8_t l); -#if OW_DEBUG -void uart_putsP(const char *addr); -void uart_puts(const char *addr); -void uart_puts_hex(uint8_t a); -void uart_puts_dec(uint8_t a, uint8_t l); - -#define OWPUTS(x) uart_puts(x) -#define OWPUTSP(x) uart_putsP(x) +#ifdef OW_DEBUG +#define OWPUTS(x) puts_P(x) +#define OWPUTSP(x) puts_P(x) +#define OWPRINTFP(fmt, ...) printf_P(fmt, ## __VA_ARGS__) #else #define OWPUTS(x) #define OWPUTSP(x) +#define OWPRINTFP(fmt, ...) #endif
--- a/1wire.c Thu Nov 22 16:02:40 2007 +0000 +++ b/1wire.c Sun Jul 06 22:19:53 2008 +0930 @@ -42,6 +42,7 @@ #include <util/delay.h> #include "1wire.h" #include "1wire-config.h" +#include "cons.h" static uint8_t OW_LastDevice = 0; static uint8_t OW_LastDiscrepancy = 0; @@ -243,7 +244,7 @@ if (do_reset) { /* reset the 1-wire * if there are no parts on 1-wire, return 0 */ - OWPUTSP(PSTR("Resetting\n\r")); + OWPUTSP(PSTR("Resetting\r\n")); switch (OWTouchReset()) { case 0: break; @@ -252,7 +253,7 @@ /* reset the search */ OW_LastDiscrepancy = 0; OW_LastFamilyDiscrepancy = 0; - OWPUTSP(PSTR("No devices on bus\n\r")); + OWPUTSP(PSTR("No devices on bus\r\n")); return OW_NOPRESENCE; break; @@ -260,7 +261,7 @@ /* reset the search */ OW_LastDiscrepancy = 0; OW_LastFamilyDiscrepancy = 0; - OWPUTSP(PSTR("Bus appears to be being held low\n\r")); + OWPUTSP(PSTR("Bus appears to be being held low\r\n")); return OW_BADWIRE; break; @@ -284,17 +285,11 @@ bit_test = OWReadBit() << 1; bit_test |= OWReadBit(); -#if OW_DEBUG - sprintf_P(errstr, PSTR("bit_test = %d\n\r"), bit_test); - OWPUTSP(errstr); -#endif + OWPRINTFP(PSTR("bit_test = %d\r\n"), bit_test); /* check for no devices on 1-wire */ if (bit_test == 3) { -#if OW_DEBUG - sprintf_P(errstr, PSTR("bit_test = %d\n\r"), bit_test); - OWPUTSP(errstr); -#endif + OWPRINTFP(PSTR("bit_test = %d\r\n"), bit_test); return(OW_BADWIRE); } else { @@ -350,19 +345,13 @@ /* if the search was successful then */ if (!(bit_number < 65) || lastcrc8) { if (lastcrc8) { -#if OW_DEBUG - sprintf_P(errstr, PSTR("Bad CRC (%d)\n\r"), lastcrc8); - OWPUTSP(errstr); -#endif + OWPRINTFP(PSTR("Bad CRC (%d)\r\n"), lastcrc8); next_result = OW_BADCRC; } else { /* search successful so set LastDiscrepancy,LastDevice,next_result */ OW_LastDiscrepancy = last_zero; OW_LastDevice = (OW_LastDiscrepancy == 0); -#if OW_DEBUG - sprintf_P(errstr, PSTR("Last device = %d\n\r"), OW_LastDevice); - OWPUTSP(errstr); -#endif + OWPRINTFP(PSTR("Last device = %d\r\n"), OW_LastDevice); next_result = OW_FOUND; } } @@ -449,7 +438,7 @@ OWDELAY_I; if (OWTouchReset() != 0) { - uart_putsP(PSTR("No presence pulse\n\r")); + cons_putsP(PSTR("No presence pulse\r\n")); return(3); } @@ -474,11 +463,11 @@ OWCRC(0x00, &crc); for (i = 0; i < len; i++) { - uart_putsP(PSTR("Programming ")); - uart_puts_hex(data[i]); - uart_putsP(PSTR(" to ")); - uart_puts_hex(start + i); - uart_putsP(PSTR("\n\r")); + cons_putsP(PSTR("Programming ")); + cons_puts_hex(data[i]); + cons_putsP(PSTR(" to ")); + cons_puts_hex(start + i); + cons_putsP(PSTR("\r\n")); OWWriteByte(data[i]); OWCRC(data[i], &crc); @@ -486,11 +475,11 @@ tmp = OWReadByte(); if (crc != tmp) { - uart_putsP(PSTR("CRC mismatch ")); - uart_puts_hex(crc); - uart_putsP(PSTR(" vs ")); - uart_puts_hex(tmp); - uart_putsP(PSTR("\n\r")); + cons_putsP(PSTR("CRC mismatch ")); + cons_puts_hex(crc); + cons_putsP(PSTR(" vs ")); + cons_puts_hex(tmp); + cons_putsP(PSTR("\r\n")); OWTouchReset(); return(3); @@ -509,11 +498,11 @@ return(-3); */ if ((!data[i] & tmp) != 0) { - uart_putsP(PSTR("Readback mismatch ")); - uart_puts_hex(data[i]); - uart_putsP(PSTR(" vs ")); - uart_puts_hex(data[i]); - uart_putsP(PSTR("\n\r")); + cons_putsP(PSTR("Readback mismatch ")); + cons_puts_hex(data[i]); + cons_putsP(PSTR(" vs ")); + cons_puts_hex(data[i]); + cons_putsP(PSTR("\r\n")); OWTouchReset(); return(3); @@ -531,3 +520,72 @@ #endif } +/* + * OWGetTemp + * + * Get the temperature from a 1wire bus module + * + * Returns temperature in hundredths of a degree or OW_TEMP_xxx on + * error. + */ +int16_t +OWGetTemp(uint8_t *ROM) { + int8_t i; + uint8_t crc, buf[9]; + int16_t temp; + int16_t tfrac; + + if (ROM[0] != OW_FAMILY_TEMP) + return OW_TEMP_WRONG_FAM; + + OWSendCmd(ROM, OW_CONVERTT_CMD); + + i = 0; + + /* Wait for the conversion */ + while (OWReadBit() == 0) + i = 1; + + /* Check that we talked to a module and it did something */ + if (i == 0) { + return OW_TEMP_NO_ROM; + } + + OWSendCmd(ROM, OW_RD_SCR_CMD); + crc = 0; + for (i = 0; i < 8; i++) { + buf[i] = OWReadByte(); + OWCRC(buf[i], &crc); + } + buf[i] = OWReadByte(); + if (crc != buf[8]) + return OW_TEMP_CRC_ERR; + temp = buf[0]; + if (buf[1] & 0x80) + temp -= 256; + + /* Chop off 0.5 degree bit */ + temp >>= 1; + + /* Calulate the fractional remainder */ + tfrac = buf[7] - buf[6]; + + /* Work in 100'th of degreess to save on floats */ + tfrac *= (int16_t)100; + + /* Divide by count */ + tfrac /= buf[7]; + + /* Subtract 0.25 deg from temp */ + tfrac += 75; + if (tfrac < 100) + temp--; + else + tfrac -= 100; + + i = temp; + temp *= 100; + temp += tfrac; + + return(temp); +}
--- a/1wire.h Thu Nov 22 16:02:40 2007 +0000 +++ b/1wire.h Sun Jul 06 22:19:53 2008 +0930 @@ -41,6 +41,7 @@ void OWCRC(uint8_t x, uint8_t *crc); void OWSendCmd(uint8_t *ROM, uint8_t cmd); uint8_t OWProgROM(uint8_t *ROM, uint8_t start, uint8_t len, uint8_t *data, uint8_t exact, uint8_t status); +int16_t OWGetTemp(uint8_t *ROM); /* Return codes for OWFirst()/OWNext() */ #define OW_BADWIRE -3 @@ -75,3 +76,9 @@ /* Family codes */ #define OW_FAMILY_ROM 0x09 #define OW_FAMILY_TEMP 0x10 + +/* Return codes for OWGetTemp */ +#define OW_TEMP_BADVAL -1000 +#define OW_TEMP_WRONG_FAM -1000 +#define OW_TEMP_CRC_ERR -1001 +#define OW_TEMP_NO_ROM -1002
--- a/Makefile Thu Nov 22 16:02:40 2007 +0000 +++ b/Makefile Sun Jul 06 22:19:53 2008 +0930 @@ -3,7 +3,7 @@ # PROG= testavr -SRCS= 1wire.c testavr.c +SRCS= 1wire.c cons.c tempctrl.c testavr.c .if defined(WITHUSB) SRCS+= usb.c CFLAGS+=-DWITHUSB @@ -16,10 +16,12 @@ CFLAGS+=-DF_CPU=16000000 #CFLAGS+= -mcall-prologues -frename-registers -fstrict-aliasing -fnew-ra -#PROGTYPE=stk500v2 -#PROGPORT=/dev/cuaU0 -PROGTYPE=alf -PROGPORT=/dev/ppi0 +#CFLAGS+=-DOW_DEBUG + +#PROGTYPE=alf +#PROGPORT=/dev/ppi0 +PROGTYPE=dragon_jtag +PROGPORT=usb PROGOPTS=-p ${PART} -c ${PROGTYPE} -E vcc,noreset -q -P ${PROGPORT} .include "Makefile.avr"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cons.c Sun Jul 06 22:19:53 2008 +0930 @@ -0,0 +1,180 @@ +/* + * Console code for AVR board + * + * 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 <ctype.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include "cons.h" + +#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) + +/* Receive buffer storage */ +consbuf_t cmd; + +/* + * Stub to use with fdevopen + * + * We ignore f and always succeed + */ +static int _putc(char c, FILE *f) { + cons_putc(c); + return(0); +} + +/* + * Stub to use with fdevopen + * + * We ignore f and always succeed + */ +static int _getc(FILE *f) { + return(cons_getc()); +} + +void +cons_init(void) { + UBRRH = UART_BAUD_SELECT(38400, F_CPU) >> 8; + UBRRL = (uint8_t)UART_BAUD_SELECT(38400, F_CPU); + + /* Enable receiver and transmitter. Turn on rx interrupts */ + UCSRA = 0; + UCSRB = _BV(RXEN) | _BV(TXEN) | _BV(RXCIE); + UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); + + fdevopen(_putc, NULL); /* Open stdout */ + fdevopen(NULL, _getc); /* Open stdin */ +} + +int +cons_putc(char c) { + loop_until_bit_is_set(UCSRA, UDRE); + UDR = c; + + return(0); +} + +void +cons_putsP(const char *addr) { + char c; + + while ((c = pgm_read_byte_near(addr++))) + cons_putc(c); +} + +void +cons_puts(const char *addr) { + while (*addr) + cons_putc(*addr++); +} + +void +cons_puts_dec(uint8_t a, uint8_t l) { + char s[4]; + + if (l && a < 10) + cons_putsP(PSTR("0")); + cons_puts(utoa(a, s, 10)); +} + +void +cons_puts_hex(uint8_t a) { + char s[3]; + + if (a < 0x10) + cons_putc('0'); + + cons_puts(utoa(a, s, 16)); +} + +char +cons_getc(void) { + while (!(UCSRA & _BV(RXC))) + ; + + return (UDR); +} + +/* 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'; + cons_putsP(PSTR("\r\n")); + cmd.len = cmd.state; + cmd.state = 255; + continue; + } + + /* Backspace/delete */ + if (c == 0x08 || c == 0x7f) { + if (cmd.state > 0) { + cmd.state--; + cons_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 */ + cons_putc(cmd.buf[cmd.state]); + + cmd.state++; + /* Over flow? */ + if (cmd.state == ((sizeof(cmd.buf) / sizeof(cmd.buf[0])) - 1)) { + cons_putsP(PSTR("\r\nLine too long")); + cmd.state = 0; + continue; + } + } +} + +/* Tx complete */ +ISR(USART_TXC_vect) { + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cons.h Sun Jul 06 22:19:53 2008 +0930 @@ -0,0 +1,44 @@ +/* + * Console code headers + * + * 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. + */ + +typedef volatile struct { + char buf[40]; + uint8_t state; + uint8_t len; +} consbuf_t; + +extern consbuf_t cmd; + +void cons_init(void); +void cons_putsP(const char *addr); +void cons_puts(const char *addr); +int cons_putc(char c); +void cons_puts_dec(uint8_t a, uint8_t l); +void cons_puts_hex(uint8_t a); +char cons_getc(void); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tempctrl.c Sun Jul 06 22:19:53 2008 +0930 @@ -0,0 +1,544 @@ +/* + * Temperature control logic + * + * 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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include <avr/eeprom.h> +#include <util/crc16.h> + +#include "cons.h" +#include "1wire.h" +#include "tempctrl.h" + +/* Helpers for our number system */ +#define GETWHOLE(x) ((x) / 100) +#define GETFRAC(x) ((x) - (GETWHOLE(x) * 100)) + +typedef struct { + int32_t sec; + int32_t usec; +} time_t; + +/* Holds all the settings needed */ +typedef struct { + uint8_t fermenter_ROM[8]; + uint8_t fridge_ROM[8]; + uint8_t ambient_ROM[8]; + int16_t target_temp; + uint16_t hysteresis; + + /* How much to under/overshoot on heating/cooling */ + int16_t minheatovershoot; + int16_t mincoolovershoot; + + /* Minimum time the cooler can be on/off */ + int16_t mincoolontime; + int16_t mincoolofftime; + + /* Minimum time the heater can be on/off */ + int16_t minheatontime; + int16_t minheatofftime; + +#define TC_MODE_AUTO 'a' /* Automatic control */ +#define TC_MODE_HEAT 'h' /* Force heating */ +#define TC_MODE_COOL 'c' /* Force cooling */ +#define TC_MODE_IDLE 'i' /* Force idle */ +#define TC_MODE_NOTHING 'n' /* Do nothing (like idle but log nothing) */ + char mode; + + /* Bit patterns for various modes */ + uint8_t coolbits; + uint8_t heatbits; + uint8_t idlebits; + + /* Check/stale times */ + int16_t check_interval; + int16_t stale_factor; +} __attribute__((packed)) settings_t; + +/* Current settings in RAM */ +static settings_t settings; + +/* Our map of EEPROM */ +struct { + settings_t settings; + uint16_t crc; +} ee_area __attribute__((section(".eeprom"))); + +/* Defaults that are shoved into EEPROM if it isn't inited */ +const PROGMEM settings_t default_settings = { + .fermenter_ROM = { 0x10, 0xeb, 0x48, 0x21, 0x01, 0x08, 0x00, 0xdf }, + .fridge_ROM = { 0x10, 0xa6, 0x2a, 0xc4, 0x00, 0x08, 0x00, 0x11 }, + .ambient_ROM = { 0x10, 0x97, 0x1b, 0xfe, 0x00, 0x08, 0x00, 0xd1 }, + .target_temp = 1400, + .hysteresis = 100, + .minheatovershoot = 50, + .mincoolovershoot = -50, + .mincoolontime = 300, + .mincoolofftime = 600, + .minheatontime = 60, + .minheatofftime = 60, + .mode = TC_MODE_AUTO, + .coolbits = _BV(7), + .heatbits = _BV(6), + .idlebits = 0x00, + .check_interval = 10, + .stale_factor = 3 +}; + +/* Local variable declarations */ +volatile static time_t now; + +/* Local function prototypes */ +static int gettemp(const PROGMEM char *name, uint8_t *ROM, int16_t *temp, uint8_t last); +static void tempctrl_load_or_init_settings(void); +static void tempctrl_default_settings(void); +static void tempctrl_write_settings(void); +static void setstate(char state); +static const PROGMEM char*state2long(char s); + +/* + * tempctrl_init + * + * Setup timer, should be called with interrupts disabled. + * + */ +void +tempctrl_init(void) { + /* Setup timer */ + /* 16Mhz / 1024 = 15625 Hz / 125 = 125 Hz = IRQ every 8 ms */ + + /* CTC mode, no output on pin, Divide clock by 1024 */ + TCCR0 = _BV(WGM01)| _BV(CS02) | _BV(CS00); + + /* Compare with ... */ + OCR0 = 125; + + /* Enable interrupt for match on A */ + TIMSK = _BV(OCIE0); + + now.sec = 0; + now.usec = 0; + + tempctrl_load_or_init_settings(); +} + +/* + * Timer 0 Compare IRQ + * + * Update time counter + */ + +ISR(TIMER0_COMP_vect) { + now.usec += 8000; /* 1000000 * 1 / F_CPU / 1024 / 125 */ + while (now.usec > 1000000) { + now.usec -= 1000000; + now.sec++; + } +} + +/* + * tempctrl_update + * + * Should be called in a normal context, could run things that take a long time. + * (ie 1wire bus stuff) + * + */ +void +tempctrl_update(void) { + /* State variables */ + static int32_t checktime = 0; // Time of next check + static int32_t lastdata = 0; // Last time we got data + + static int16_t fermenter_temp = 0; // Fermenter temperature + static int16_t fridge_temp = 0; // Fridge temperature + static int16_t ambient_temp = 0; // Ambient temperature + // These are inited like this so we will still heat/cool when + // now < settings.minheatofftime + static int32_t lastheaton = -100000; // Last time the heater was on + static int32_t lastheatoff = -100000; // Last time the heater was off + static int32_t lastcoolon = -100000; // Last time the cooler was on + static int32_t lastcooloff = -100000; // Last time the cooler was off + static char currstate = 'i'; // Current state + + /* Temporary variables */ + int32_t t; + int16_t diff; + char nextstate; + int forced; + int stale; + + t = gettod(); + /* Time to check temperatures? */ + if (t < checktime) + return; + + checktime = t + settings.check_interval; + + /* Don't do any logging, just force idle and leave */ + if (settings.mode == TC_MODE_NOTHING) { + nextstate = 'i'; + goto setstate; + } + + /* Update our temperatures */ + printf_P(PSTR("Time: %ld, Target: %d.%02d, "), now.sec, GETWHOLE(settings.target_temp), + GETFRAC(settings.target_temp)); + + if (gettemp(PSTR("Fermenter"), settings.fermenter_ROM, &fermenter_temp, 0)) + lastdata = t; + + /* Check for stale data */ + if (lastdata + (settings.check_interval * settings.stale_factor) < t) + stale = 1; + else + stale = 0; + + gettemp(PSTR("Fridge"), settings.fridge_ROM, &fridge_temp, 0); + gettemp(PSTR("Ambient"), settings.ambient_ROM, &ambient_temp, 1); + + /* Default to remaining as we are */ + nextstate = '-'; + + /* Temperature diff, -ve => too cold, +ve => too warm */ + diff = fermenter_temp - settings.target_temp; + + switch (currstate) { + case 'i': + /* If we're idle then only heat or cool if the temperate difference is out of the + * hysteresis band + */ + if (abs(diff) > settings.hysteresis) { + if (diff < 0 && settings.minheatofftime + lastheatoff < t) + nextstate = 'h'; + else if (diff > 0 && settings.mincoolofftime + lastcooloff < t) + nextstate = 'c'; + } + break; + + case 'c': + /* Work out if we should go idle (based on min on time & overshoot) */ + if (diff + settings.mincoolovershoot < 0 && + settings.mincoolontime + lastcoolon < t) + nextstate = 'i'; + break; + + case 'h': + if (diff - settings.minheatovershoot > 0 && + settings.minheatontime + lastheaton < t) + nextstate = 'i'; + break; + + default: + printf_P(PSTR("\r\nUnknown state %c, going to idle\n"), currstate); + nextstate = 'i'; + break; + } + + /* Override if we have stale data */ + if (stale) + nextstate = 'i'; + + /* Handle state forcing */ + if (settings.mode != TC_MODE_AUTO) + forced = 1; + else + forced = 0; + + if (settings.mode == TC_MODE_IDLE) + nextstate = 'i'; + else if (settings.mode == TC_MODE_HEAT) + nextstate = 'h'; + else if (settings.mode == TC_MODE_COOL) + nextstate = 'c'; + + if (nextstate != '-') + currstate = nextstate; + + printf_P(PSTR(", State: %S, Flags: %S%S\r\n"), state2long(currstate), + forced ? PSTR("F") : PSTR(""), + stale ? PSTR("S") : PSTR("")); + + setstate: + setstate(currstate); +} + +/* + * Log a temperature & store it if valid + * + * Returns 1 if it was valid, 0 otherwise + */ +static int +gettemp(const PROGMEM char *name, uint8_t *ROM, int16_t *temp, uint8_t last) { + int16_t tmp; + + tmp = OWGetTemp(ROM); + printf_P(PSTR("%S: "), name); + if (tmp > OW_TEMP_BADVAL) { + printf_P(PSTR("%d.%02d%S"), GETWHOLE(tmp), GETFRAC(tmp), last ? PSTR("") : PSTR(", ")); + *temp = tmp; + return(1); + } else { + printf_P(PSTR("NA (%d)%S"), tmp, last ? PSTR("") : PSTR(", ")); + return(0); + } +} + +/* Return 'time of day' (really uptime) */ +int32_t +gettod(void) { + int32_t t; + + cli(); + t = now.sec; + sei(); + + return(t); +} + +/* Read the settings from EEPROM + * If the CRC fails then reload from flash + */ +static void +tempctrl_load_or_init_settings(void) { + uint8_t *dptr; + uint16_t crc, strcrc; + int i; + + crc = 0; + eeprom_busy_wait(); + eeprom_read_block(&settings, &ee_area.settings, sizeof(settings_t)); + strcrc = eeprom_read_word(&ee_area.crc); + + dptr = (uint8_t *)&settings; + + for (i = 0; i < sizeof(settings_t); i++) + crc = _crc16_update(crc, dptr[i]); + + /* All OK? */ + if (crc == strcrc) + return; + + printf_P(PSTR("CRC mismatch got 0x%04x vs 0x%04x, setting defaults\r\n"), crc, strcrc); + tempctrl_default_settings(); + tempctrl_write_settings(); +} + +/* Load in the defaults from flash */ +static void +tempctrl_default_settings(void) { + memcpy_P(&settings, &default_settings, sizeof(settings_t)); +} + +/* Write the current settings out to EEPROM */ +static void +tempctrl_write_settings(void) { + uint16_t crc; + uint8_t *dptr; + int i; + + eeprom_busy_wait(); + eeprom_write_block(&settings, &ee_area.settings, sizeof(settings_t)); + + dptr = (uint8_t *)&settings; + crc = 0; + for (i = 0; i < sizeof(settings_t); i++) + crc = _crc16_update(crc, dptr[i]); + + eeprom_write_word(&ee_area.crc, crc); +} + +/* Set the relays to match the desired state */ +static void +setstate(char state) { + switch (state) { + case 'c': + PORTC = settings.coolbits; + break; + + case 'h': + PORTC = settings.heatbits; + break; + + default: + printf_P(PSTR("Unknown state %c, setting idle\r\n"), state); + /* fallthrough */ + + case 'i': + PORTC = settings.idlebits; + break; + } +} + +/* Handle user command + * + */ +void +tempctrl_cmd(char *buf) { + char cmd[6]; + int16_t data; + int i; + + i = sscanf_P(buf, PSTR("tc %5s %d"), cmd, &data); + + if (i == 1) { + if (!strcasecmp_P(cmd, PSTR("help"))) { + printf_P(PSTR( + "tc help This help\r\n" + "tc save Save settings to EEPROM\r\n" + "tc load Load or default settings from EEPROM\r\n" + "tc dflt Load defaults from flash\r\n" + "tc list List current settings\r\n" + "tc mode [achin] Change control mode, must be one of\r\n" + " a Auto\r\n" + " c Always cool\r\n" + " h Always heat\r\n" + " i Always idle\r\n" + " n Like idle but don't log anything\r\n" + "\r\n" + "tc X Y Set X to Y where X is one of\r\n" + " targ Target temperature\r\n" + " hys Hysteresis range\r\n" + " mhov Minimum heat overshoot\r\n" + " mcov Minimum cool overshoot\r\n" + " mcon Minimum cool on time\r\n" + " mcoff Minimum cool off time\r\n" + " mhin Minimum heat on time\r\n" + " mhoff Minimum heat off time\r\n" + " Times are in seconds\r\n" + " Temperatures are in hundredths of degrees Celcius\r\n" + )); + return; + } + + if (!strcasecmp_P(cmd, PSTR("save"))) { + tempctrl_write_settings(); + return; + } + if (!strcasecmp_P(cmd, PSTR("load"))) { + tempctrl_load_or_init_settings(); + return; + } + if (!strcasecmp_P(cmd, PSTR("dflt"))) { + tempctrl_default_settings(); + return; + } + if (!strcasecmp_P(cmd, PSTR("list"))) { + printf_P(PSTR("Fermenter ROM ID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n" + "Fridge ROM ID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n" + "Ambient ROM ID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n" + "Target - %d, Hystersis - %d\r\n" + "Min heat overshoot - %d, Min cool overshoot - %d\r\n" + "Min cool on time - %d, Min cool off time - %d\r\n" + "Min heat on time - %d, Min heat off time -%d\r\n"), + settings.fermenter_ROM[0], settings.fermenter_ROM[1], settings.fermenter_ROM[2], settings.fermenter_ROM[3], + settings.fermenter_ROM[4], settings.fermenter_ROM[5], settings.fermenter_ROM[6], settings.fermenter_ROM[7], + settings.fridge_ROM[0], settings.fridge_ROM[1], settings.fridge_ROM[2], settings.fridge_ROM[3], + settings.fridge_ROM[4], settings.fridge_ROM[5], settings.fridge_ROM[6], settings.fridge_ROM[7], + settings.ambient_ROM[0], settings.ambient_ROM[1], settings.ambient_ROM[2], settings.ambient_ROM[3], + settings.ambient_ROM[4], settings.ambient_ROM[5], settings.ambient_ROM[6], settings.ambient_ROM[7], + settings.target_temp, settings.hysteresis, + settings.minheatovershoot, settings.mincoolovershoot, + settings.mincoolontime, settings.minheatontime, + settings.minheatontime, settings.minheatofftime); + return; + } + if (!strcasecmp_P(cmd, PSTR("mode"))) { + switch (buf[8]) { + case TC_MODE_AUTO: + case TC_MODE_HEAT: + case TC_MODE_COOL: + case TC_MODE_IDLE: + case TC_MODE_NOTHING: + settings.mode = buf[8]; + break; + + default: + printf_P(PSTR("Unknown mode character '%c'\r\n"), buf[8]); + break; + } + return; + } + + } + + if (i != 2) { + printf_P(PSTR("Unable to parse command\r\n")); + return; + } + + if (!strcasecmp_P(cmd, PSTR("targ"))) { + settings.target_temp = data; + } else if (!strcasecmp_P(cmd, PSTR("hys"))) { + settings.hysteresis = data; + } else if (!strcasecmp_P(cmd, PSTR("mhov"))) { + settings.minheatovershoot = data; + } else if (!strcasecmp_P(cmd, PSTR("mcov"))) { + settings.mincoolovershoot = data; + } else if (!strcasecmp_P(cmd, PSTR("mcon"))) { + settings.mincoolontime = data; + } else if (!strcasecmp_P(cmd, PSTR("mcoff"))) { + settings.mincoolofftime = data; + } else if (!strcasecmp_P(cmd, PSTR("mhon"))) { + settings.minheatontime = data; + } else if (!strcasecmp_P(cmd, PSTR("mhoff"))) { + settings.minheatofftime = data; + } else { + printf_P(PSTR("Unknown setting\r\n")); + return; + } +} + +static const PROGMEM char* +state2long(char s) { + switch (s) { + case 'i': + return PSTR("idle"); + break; + + case 'c': + return PSTR("cool"); + break; + + case 'h': + return PSTR("heat"); + break; + + case '-': + return PSTR("-"); + break; + + default: + return PSTR("unknown"); + break; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tempctrl.h Sun Jul 06 22:19:53 2008 +0930 @@ -0,0 +1,32 @@ +/* + * Temperature control headers + * + * 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. + */ + +void tempctrl_init(void); +void tempctrl_update(void); +void tempctrl_cmd(char *cmd); +int32_t gettod(void);
--- a/testavr.c Thu Nov 22 16:02:40 2007 +0000 +++ b/testavr.c Sun Jul 06 22:19:53 2008 +0930 @@ -1,9 +1,7 @@ /* * Test various AVR bits and pieces * - * $Id$ - * - * Copyright (c) 2004 + * Copyright (c) 2008 * Daniel O'Connor <darius@dons.net.au>. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,101 +29,27 @@ #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 "cons.h" #include "1wire.h" #ifdef WITHUSB #include "usb.h" #endif - -#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) -#define UART_BAUD_RATE 38400 +#include "tempctrl.h" 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("\r\n")); - 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("\r\nLine too long")); - cmd.state = 0; - continue; - } - } -} - -/* Tx complete */ -ISR(USART_TXC_vect) { - -} - int main(void) { /* Disable interrupts while we frob stuff */ cli(); -#if 1 +#if 0 /* Disable JTAG (yes twice) */ MCUCSR |= _BV(JTD); MCUCSR |= _BV(JTD); @@ -155,16 +79,13 @@ OWInit(); /* Init UART */ - UBRRH = UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) >> 8; - UBRRL = (uint8_t)UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU); + cons_init(); - /* 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("\r\n\r\n===============\r\n" - "Inited!\r\n\r\n")); + printf_P(PSTR("\r\n\r\n===============\r\n" + "Inited!\r\n\r\n")); + tempctrl_init(); + /* Ready to go! */ sei(); @@ -172,34 +93,36 @@ DDRA = 0xff; DDRC = 0xff; while (1) { - uart_putsP(PSTR("1\r\n")); + printf_P(PSTR("1\r\n")); PORTA = 0xff; - uart_putsP(PSTR("2\r\n")); + printf_P(PSTR("2\r\n")); PORTC = 0x00; - uart_putsP(PSTR("3\r\n")); + printf_P(PSTR("3\r\n")); _delay_us(1); - uart_putsP(PSTR("4\r\n")); + printf_P(PSTR("4\r\n")); PORTA = 0x80; - uart_putsP(PSTR("5\r\n")); + printf_P(PSTR("5\r\n")); PORTC = 0xff; - uart_putsP(PSTR("6\r\n")); + printf_P(PSTR("6\r\n")); } #endif #ifdef WITHUSB - uart_putsP(PSTR("Calling usb_init\r\n")); + printf_P(PSTR("Calling usb_init\r\n")); usb_init(); + printf_P(PSTR("done\r\n")); + _delay_us(1000); #endif - uart_putsP(PSTR("done\r\n")); - _delay_us(1000); - uart_putsP(PSTR("> ")); + printf_P(PSTR("> ")); cmd.state = 0; /* Wait for user input or an "interrupt" */ while (1) { + tempctrl_update(); + if (cmd.state == 255) { process_cmd(); - uart_putsP(PSTR("> ")); + printf_P(PSTR("> ")); /* Allow new characters to be processed */ cmd.state = 0; } @@ -224,18 +147,19 @@ return; if (cmd.buf[0] == '?') { - uart_putsP(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" - "out port val Write to a port\r\n" - "ddr port [val] Read/write DDR for a port\r\n")); - + 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" + "out port val Write to a port\r\n" + "ddr port [val] Read/write DDR for a port\r\n" + "tc ... Temperature control related (tc help for more)\r\n")); + return; } @@ -244,40 +168,34 @@ goto badcmd; if (cmd.buf[0] == 'r' && cmd.buf[1] == 's') { - uart_putsP(PSTR("Resetting... ")); + printf_P(PSTR("Resetting... ")); if (OWTouchReset() == 1) - uart_putsP(PSTR("No presence pulse found\r\n")); + printf_P(PSTR("No presence pulse found\r\n")); else - uart_putsP(PSTR("Presence pulse found\r\n")); + printf_P(PSTR("Presence pulse found\r\n")); } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'e') { if (OWReadBit()) - uart_putsP(PSTR("Read a 1\r\n")); + printf_P(PSTR("Read a 1\r\n")); else - uart_putsP(PSTR("Read a 0\r\n")); + printf_P(PSTR("Read a 0\r\n")); } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'b') { - uart_putsP(PSTR("Read a 0x")); - uart_puts_hex(OWReadByte()); - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("Read a 0x%02x\r\n"), OWReadByte()); } 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\r\n")); - else - uart_putsP(PSTR("0\r\n")); + printf_P(PSTR("Wrote a %c\r\n"), arg ? '1' : '0'); } 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] == 'r' && cmd.buf[1] == 't') { if (cmd.len < 26) { - uart_putsP(PSTR("Unable to parse ROM ID\r\n")); + printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } if (OWTouchReset() != 0) { - uart_putsP(PSTR("No presence\r\n")); + printf_P(PSTR("No presence\r\n")); return; } @@ -285,12 +203,12 @@ ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16); if (ROM[0] != OW_FAMILY_ROM) { - uart_putsP(PSTR("ROM specified isn't a DS2502\r\n")); + printf_P(PSTR("ROM specified isn't a DS2502\r\n")); return; } if (OWTouchReset() != 0) { - uart_putsP(PSTR("No presence\r\n")); + printf_P(PSTR("No presence\r\n")); return; } @@ -306,25 +224,24 @@ OWCRC(0x00, &crc); if (crc != OWReadByte()) { - uart_putsP(PSTR("CRC mismatch on command & address\r\n")); + printf_P(PSTR("CRC mismatch on command & address\r\n")); return; } crc = 0; for (i = 0; i < 8; i++) { temp = OWReadByte(); - uart_puts_hex(temp); + printf_P(PSTR("%02x "), temp); OWCRC(temp, &crc); - uart_putsP(PSTR(" ")); } - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("\r\n")); if (crc != OWReadByte()) { - uart_putsP(PSTR("CRC mismatch on data\r\n")); + printf_P(PSTR("CRC mismatch on data\r\n")); return; } } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'e') { if (cmd.len < 26) { - uart_putsP(PSTR("Unable to parse ROM ID\r\n")); + printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } @@ -332,7 +249,7 @@ ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16); if (ROM[0] != OW_FAMILY_ROM) { - uart_putsP(PSTR("ROM specified isn't a ROM\r\n")); + printf_P(PSTR("ROM specified isn't a ROM\r\n")); return; } @@ -341,17 +258,15 @@ buf[2] = (int)strtol((char *)cmd.buf + 33, (char **)NULL, 16); if (OWTouchReset() != 0) { - uart_putsP(PSTR("No presence\r\n")); + printf_P(PSTR("No presence\r\n")); return; } i = OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0); - uart_putsP(PSTR("OWProgROM returned ")); - uart_puts_dec(i, 0); - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("OWProgROM returned %d\r\n"), i); } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'r') { if (cmd.len < 26) { - uart_putsP(PSTR("Unable to parse ROM ID\r\n")); + printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } @@ -359,7 +274,7 @@ ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16); if (ROM[0] != OW_FAMILY_ROM) { - uart_putsP(PSTR("ROM specified isn't a ROM\r\n")); + printf_P(PSTR("ROM specified isn't a ROM\r\n")); return; } @@ -374,7 +289,7 @@ OWCRC(0x00, &crc); if (crc != OWReadByte()) { - uart_putsP(PSTR("CRC mismatch on command & address\r\n")); + printf_P(PSTR("CRC mismatch on command & address\r\n")); return; } @@ -383,29 +298,29 @@ buf[1] = OWReadByte(); if (buf[0] > 0) { if (buf[0] % 16 != 0) - uart_putsP(PSTR(" ")); + printf_P(PSTR(" ")); else - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("\r\n")); } - uart_puts_hex(buf[1]); + printf_P(PSTR("%02x"), buf[1]); OWCRC(buf[1], &crc); } - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("\r\n")); if (crc != OWReadByte()) { - uart_putsP(PSTR("CRC mismatch on data\r\n")); + printf_P(PSTR("CRC mismatch on data\r\n")); return; } } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'c') { if (cmd.len < 5) { - uart_putsP(PSTR("No arguments\r\n")); + printf_P(PSTR("No arguments\r\n")); return; } arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); if (arg == 0) { - uart_putsP(PSTR("Unparseable command\r\n")); + printf_P(PSTR("Unparseable command\r\n")); return; } @@ -415,7 +330,7 @@ } if (i < 29) { - uart_putsP(PSTR("Can't parse ROM ID\r\n")); + printf_P(PSTR("Can't parse ROM ID\r\n")); return; } for (i = 0; i < 8; i++) @@ -424,7 +339,7 @@ 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\r\n")); + printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } @@ -432,16 +347,17 @@ 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\r\n")); + printf_P(PSTR("ROM specified isn't a temperature sensor\r\n")); return; } OWSendCmd(ROM, OW_CONVERTT_CMD); i = 0; /* Wait for the conversion */ - while (OWReadBit() == 0) { - i++; - } + while (OWReadBit() == 0) + i = 1; + + OWSendCmd(ROM, OW_RD_SCR_CMD); crc = 0; for (i = 0; i < 9; i++) { @@ -451,17 +367,10 @@ } if (crc != buf[8]) { - uart_putsP(PSTR("CRC mismatch\r\n")); + printf_P(PSTR("CRC mismatch\r\n")); 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("\r\n")); -#else /* 0 Temperature LSB * 1 Temperature MSB * 2 Th @@ -473,10 +382,8 @@ * 8 CRC */ #if 0 - for (i = 0; i < 9; i++) { - uart_puts_dec(buf[i], 0); - uart_putsP(PSTR("\r\n")); - } + for (i = 0; i < 9; i++) + printf_P(PSTR("%d\r\n"), buf[i]); #endif temp = buf[0]; if (buf[1] & 0x80) @@ -493,16 +400,7 @@ 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("\r\n")); - -#endif + printf_P(PSTR("%d.%02d\r\n"), temp, tfrac); } else if (cmd.buf[0] == 's' && cmd.buf[1] == 'r') { memset(ROM, 0, 8); @@ -510,15 +408,15 @@ do { switch (i) { case OW_BADWIRE: - uart_putsP(PSTR("Presence pulse, but no module found, bad module/cabling?\r\n")); + printf_P(PSTR("Presence pulse, but no module found, bad module/cabling?\r\n")); break; case OW_NOPRESENCE: - uart_putsP(PSTR("No presence pulse found\r\n")); + printf_P(PSTR("No presence pulse found\r\n")); break; case OW_BADCRC: - uart_putsP(PSTR("Bad CRC\r\n")); + printf_P(PSTR("Bad CRC\r\n")); break; case OW_NOMODULES: @@ -526,19 +424,15 @@ break; default: - uart_putsP(PSTR("Unknown error from 1 wire library\r\n")); + printf_P(PSTR("Unknown error from 1 wire library\r\n")); 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("\r\n")); + 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); @@ -561,12 +455,10 @@ break; default: - uart_putsP(PSTR("Unknown port\r\n")); + printf_P(PSTR("Unknown port\r\n")); return; } - uart_putsP(PSTR("0x")); - uart_puts_hex(crc); - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("0x%02x\r\n"), crc); } else if (cmd.buf[0] == 'o' && cmd.buf[1] == 'u') { crc = strtol((char *)cmd.buf + 8, (char **)NULL, 16); switch (tolower(cmd.buf[4])) { @@ -587,12 +479,10 @@ break; default: - uart_putsP(PSTR("Unknown port\r\n")); + printf_P(PSTR("Unknown port\r\n")); return; } - uart_putsP(PSTR("0x")); - uart_puts_hex(crc); - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(cmd.buf[4]), crc); } else if (cmd.buf[0] == 'd' && cmd.buf[1] == 'd') { crc = strtol((char *)cmd.buf + 8, (char **)NULL, 16); switch (tolower(cmd.buf[4])) { @@ -613,68 +503,20 @@ break; default: - uart_putsP(PSTR("Unknown port\r\n")); + printf_P(PSTR("Unknown port\r\n")); return; } - uart_putsP(PSTR("0x")); - uart_puts_hex(crc); - uart_putsP(PSTR("\r\n")); + printf_P(PSTR("0x%02x\r\n"), crc); + } else if (cmd.buf[0] == 't' && cmd.buf[1] == 'c') { + tempctrl_cmd((char *)cmd.buf); #ifdef WITHUSB } else if (cmd.buf[0] == 'u' && cmd.buf[1] == 's') { usb_gendata(); #endif } else { badcmd: - uart_putsP(PSTR("Unknown command, ? for a list\r\n")); + printf_P(PSTR("Unknown command, ? for a list\r\n")); } } -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); -} -
--- a/usb.c Thu Nov 22 16:02:40 2007 +0000 +++ b/usb.c Sun Jul 06 22:19:53 2008 +0930 @@ -285,7 +285,7 @@ uart_putsP(PSTR("PDIUSBD12 does not appear to be present/working, chip ID = 0x")); uart_puts_hex(buffer[0]); uart_puts_hex(buffer[1]); - uart_putsP(PSTR(", expected 0x1210\n\r")); + uart_putsP(PSTR(", expected 0x1210\r\n")); return; } @@ -333,16 +333,16 @@ if (irq[0] == 0) return; - uart_putsP(PSTR("usb_intr() called\n\r")); + uart_putsP(PSTR("usb_intr() called\r\n")); if (irq[0] & D12_INT_BUS_RESET) { - uart_putsP(PSTR("Bus reset\n\r")); + uart_putsP(PSTR("Bus reset\r\n")); usb_init(); return; } if (irq[0] & D12_INT_SUSPEND) { - uart_putsP(PSTR("Suspend change\n\r")); + uart_putsP(PSTR("Suspend change\r\n")); } if (irq[0] & D12_INT_EP0_IN) { @@ -350,7 +350,7 @@ if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) { uart_putsP(PSTR("EP0_IN error ")); uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1); - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); } /* Handle any outgoing data for EP0 */ @@ -363,7 +363,7 @@ if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) { uart_putsP(PSTR("EP0_OUT error ")); uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1); - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); } if (buffer[0] & D12_LAST_TRAN_SETUP) @@ -379,17 +379,17 @@ if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) { uart_putsP(PSTR("EP1_IN error ")); uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1); - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); } /* Select endpoint */ d12_read_cmd(D12_ENDPOINT_EP1_IN, buffer, 1); if (buffer[0] & 0x01) - uart_putsP(PSTR("EP1_IN is full\n\r")); + uart_putsP(PSTR("EP1_IN is full\r\n")); if (buffer[0] & 0x02) - uart_putsP(PSTR("EP1_IN is stalled\n\r")); + uart_putsP(PSTR("EP1_IN is stalled\r\n")); d12_write_endpt(D12_ENDPOINT_EP1_IN, NULL, 0); } @@ -400,7 +400,7 @@ if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) { uart_putsP(PSTR("EP1_OUT error ")); uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1); - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); } d12_receive_data_ep1(); @@ -411,7 +411,7 @@ if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) { uart_putsP(PSTR("EP2_IN error ")); uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1); - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); } d12_send_data_ep2(); @@ -422,7 +422,7 @@ if ((buffer[0] & D12_LAST_TRAN_ERRMSK) != 0) { uart_putsP(PSTR("EP2_OUT error ")); uart_puts_hex((buffer[0] & D12_LAST_TRAN_ERRMSK) >> 1); - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); } d12_receive_data_ep2(); } @@ -705,7 +705,7 @@ */ void reset(void) { - uart_putsP(PSTR("Resetting!\n\r")); + uart_putsP(PSTR("Resetting!\r\n")); _delay_us(1000); /* Disable the interrupts */ @@ -848,7 +848,7 @@ if ((status & 0x01) != 0) { uart_putsP(PSTR("Endpoint ")); uart_puts_dec(endpt / 2, 0); - uart_putsP(PSTR(" IN is full..\n\r")); + uart_putsP(PSTR(" IN is full..\r\n")); return; } @@ -964,7 +964,7 @@ uart_putsP(PSTR("Got ")); uart_puts_dec(bytes, 0); - uart_putsP(PSTR(" bytes from the host\n\r")); + uart_putsP(PSTR(" bytes from the host\r\n")); parsebuf(packet2, D12_ENDPOINT_EP2_IN); @@ -1002,7 +1002,7 @@ uart_putsP(PSTR("Got ")); uart_puts_dec(bytes, 0); - uart_putsP(PSTR(" bytes from the host\n\r")); + uart_putsP(PSTR(" bytes from the host\r\n")); /* Allow new packets to be accepted */ d12_write_cmd(D12_CLEAR_BUFFER, NULL, 0); @@ -1016,24 +1016,24 @@ switch (buffer[0]) { case 0x00: - uart_putsP(PSTR("OWTouchReset()\n\r")); + uart_putsP(PSTR("OWTouchReset()\r\n")); buffer[0] = OWTouchReset(); d12_write_endpt(ep, buffer, 1); break; case 0x01: - uart_putsP(PSTR("OWFirst()\n\r")); + uart_putsP(PSTR("OWFirst()\r\n")); buffer[0] = OWFirst(&buffer[1], 1, 0); for (i = 0; i < 9; i++) { uart_puts_hex(buffer[i + 1]); uart_putsP(PSTR(" ")); } - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); d12_write_endpt(ep, buffer, 9); break; case 0x02: - uart_putsP(PSTR("OWNext()\n\r")); + uart_putsP(PSTR("OWNext()\r\n")); buffer[0] = OWNext(&buffer[1], 1, 0); d12_write_endpt(ep, buffer, 9); break; @@ -1046,13 +1046,13 @@ uart_putsP(PSTR(":")); } - uart_putsP(PSTR("\n\r")); + uart_putsP(PSTR("\r\n")); d12_write_endpt(ep, buffer, 9); break; default: - uart_putsP(PSTR("Unknown command on endpoint 1\n\r")); + uart_putsP(PSTR("Unknown command on endpoint 1\r\n")); break; } }