Mercurial > templog
changeset 203:11a1b59b0624
Move old stuff to its own place
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 30 Mar 2014 20:21:56 +0800 |
parents | 6dd157a12035 |
children | 2023bd995276 |
files | Makefile crc8.c crc8.h ds18x20.h main.c old/Makefile old/crc8.c old/crc8.h old/ds18x20.h old/main.c old/onewire.c old/onewire.h old/server/config.py old/server/dump.py old/server/ts.py old/server/utils.py old/simple_ds18b20.c old/simple_ds18b20.h onewire.c onewire.h server/config.py server/dump.py server/ts.py server/utils.py simple_ds18b20.c simple_ds18b20.h |
diffstat | 26 files changed, 2700 insertions(+), 2700 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Sun Mar 30 20:20:30 2014 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -# Name: Makefile -# Author: <insert your name here> -# Copyright: <insert your copyright message here> -# License: <insert your license reference here> - -# This is a prototype Makefile. Modify it according to your needs. -# You should at least check the settings for -# DEVICE ....... The AVR device you compile for -# CLOCK ........ Target AVR clock rate in Hertz -# OBJECTS ...... The object files created from your source files. This list is -# usually the same as the list of source files with suffix ".o". -# PROGRAMMER ... Options to avrdude which define the hardware you use for -# uploading to the AVR and the interface where this hardware -# is connected. We recommend that you leave it undefined and -# add settings like this to your ~/.avrduderc file: -# default_programmer = "stk500v2" -# default_serial = "avrdoper" -# FUSES ........ Parameters for avrdude to flash the fuses appropriately. - -DEVICE = atmega328 -PROGDEVICE = atmega328p -CLOCK = 2000000 -PROGRAMMER = #-c stk500v2 -P avrdoper -PROGRAMMER = -c stk500 -P ~/dev/stk500 -p $(PROGDEVICE) -B 2 -SOURCE_1WIRE = onewire.c simple_ds18b20.c crc8.c -SOURCE = main.c -SOURCE += $(SOURCE_1WIRE) -LIBS = -lm - -# default but 2mhz -FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x62:m - -# ATMega8 fuse bits used above (fuse bits for other devices are different!): -# Example for 8 MHz internal oscillator -# Fuse high byte: -# 0xd9 = 1 1 0 1 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000) -# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 -# | | | | | +-------- BOOTSZ1 -# | | | | +---------- EESAVE (set to 0 to preserve EEPROM over chip erase) -# | | | +-------------- WDTON -# | | +---------------- SPIEN (if set to 1, serial programming is disabled) -# | +------------------ DWEN -# +-------------------- RSTDISBL (if set to 0, RESET pin is disabled) -# Fuse low byte: -# 0x62 = 0 1 1 0 0 0 1 0 -# ^ ^ \ / \--+--/ -# | | | +------- CKSEL 3..0 (8M internal RC) -# | | +--------------- SUT 1..0 (slowly rising power) -# | +------------------ CKOUT -# +-------------------- CLKDIV8 -# -# For computing fuse byte values for other devices and options see -# the fuse bit calculator at http://www.engbedded.com/fusecalc/ - - -# Tune the lines below only if you know what you are doing: - -AVRDUDE = avrdude $(PROGRAMMER) -COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -g -std=c99 -mcall-prologues -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--relax --combine -fwhole-program -Wl,-u,vfprintf -lprintf_flt -lm - -# symbolic targets: -all: main.hex - -.c.o: - $(COMPILE) -c $< -o $@ - -.S.o: - $(COMPILE) -x assembler-with-cpp -c $< -o $@ -# "-x assembler-with-cpp" should not be necessary since this is the default -# file type for the .S (with capital S) extension. However, upper case -# characters are not always preserved on Windows. To ensure WinAVR -# compatibility define the file type manually. - -.c.s: - $(COMPILE) -S $< -o $@ - -flash: all - $(AVRDUDE) -U flash:w:main.hex:i - -checkprog: - $(AVRDUDE) -v - -fuse: - $(AVRDUDE) $(FUSES) - -# Xcode uses the Makefile targets "", "clean" and "install" -install: flash - -# if you use a bootloader, change the command below appropriately: -load: all - bootloadHID main.hex - -clean: - rm -f main.hex main.elf $(OBJECTS) - -# file targets: -main.elf: $(SOURCE) - $(COMPILE) -o main.elf $(SOURCE) $(LIBS) - -main.hex: main.elf - rm -f main.hex - avr-objcopy -j .text -j .data -O ihex main.elf main.hex - avr-size --format=avr --mcu=$(DEVICE) main.elf -# If you have an EEPROM section, you must also create a hex file for the -# EEPROM and add it to the "flash" target. - -# Targets for code debugging and analysis: -disasm: main.elf - avr-objdump -d main.elf - -cpp: - $(COMPILE) -E main.c
--- a/crc8.c Sun Mar 30 20:20:30 2014 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* please read copyright-notice at EOF */ - -#include <stdint.h> - -#define CRC8INIT 0x00 -#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 - -uint8_t crc8( uint8_t *data, uint16_t number_of_bytes_in_data ) -{ - uint8_t crc; - uint16_t loop_count; - uint8_t bit_counter; - uint8_t b; - uint8_t feedback_bit; - - crc = CRC8INIT; - - for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) - { - b = data[loop_count]; - - bit_counter = 8; - do { - feedback_bit = (crc ^ b) & 0x01; - - if ( feedback_bit == 0x01 ) { - crc = crc ^ CRC8POLY; - } - crc = (crc >> 1) & 0x7F; - if ( feedback_bit == 0x01 ) { - crc = crc | 0x80; - } - - b = b >> 1; - bit_counter--; - - } while (bit_counter > 0); - } - - return crc; -} - -/* -This code is from Colin O'Flynn - Copyright (c) 2002 -only minor changes by M.Thomas 9/2004 - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/
--- a/crc8.h Sun Mar 30 20:20:30 2014 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -#ifndef CRC8_H_ -#define CRC8_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -uint8_t crc8( uint8_t* data, uint16_t number_of_bytes_in_data ); - -#ifdef __cplusplus -} -#endif - -#endif - -/* -This is based on code from : - -Copyright (c) 2002 Colin O'Flynn - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -
--- a/ds18x20.h Sun Mar 30 20:20:30 2014 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -#ifndef DS18X20_H_ -#define DS18X20_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdlib.h> -#include <stdint.h> - -// DS18x20 EERPROM support disabled(0) or enabled(1) : -#define DS18X20_EEPROMSUPPORT 1 -// decicelsius functions disabled(0) or enabled(1): -#define DS18X20_DECICELSIUS 1 -// max. resolution functions disabled(0) or enabled(1): -#define DS18X20_MAX_RESOLUTION 1 -// extended output via UART disabled(0) or enabled(1) : -#define DS18X20_VERBOSE 1 - - -/* return values */ -#define DS18X20_OK 0x00 -#define DS18X20_ERROR 0x01 -#define DS18X20_START_FAIL 0x02 -#define DS18X20_ERROR_CRC 0x03 - -#define DS18X20_INVALID_DECICELSIUS 2000 - -#define DS18X20_POWER_PARASITE 0x00 -#define DS18X20_POWER_EXTERN 0x01 - -#define DS18X20_CONVERSION_DONE 0x00 -#define DS18X20_CONVERTING 0x01 - -/* DS18X20 specific values (see datasheet) */ -#define DS18S20_FAMILY_CODE 0x10 -#define DS18B20_FAMILY_CODE 0x28 -#define DS1822_FAMILY_CODE 0x22 - -#define DS18X20_CONVERT_T 0x44 -#define DS18X20_READ 0xBE -#define DS18X20_WRITE 0x4E -#define DS18X20_EE_WRITE 0x48 -#define DS18X20_EE_RECALL 0xB8 -#define DS18X20_READ_POWER_SUPPLY 0xB4 - -#define DS18B20_CONF_REG 4 -#define DS18B20_9_BIT 0 -#define DS18B20_10_BIT (1<<5) -#define DS18B20_11_BIT (1<<6) -#define DS18B20_12_BIT ((1<<6)|(1<<5)) -#define DS18B20_RES_MASK ((1<<6)|(1<<5)) - -// undefined bits in LSB if 18B20 != 12bit -#define DS18B20_9_BIT_UNDF ((1<<0)|(1<<1)|(1<<2)) -#define DS18B20_10_BIT_UNDF ((1<<0)|(1<<1)) -#define DS18B20_11_BIT_UNDF ((1<<0)) -#define DS18B20_12_BIT_UNDF 0 - -// conversion times in milliseconds -#define DS18B20_TCONV_12BIT 750 -#define DS18B20_TCONV_11BIT DS18B20_TCONV_12_BIT/2 -#define DS18B20_TCONV_10BIT DS18B20_TCONV_12_BIT/4 -#define DS18B20_TCONV_9BIT DS18B20_TCONV_12_BIT/8 -#define DS18S20_TCONV DS18B20_TCONV_12_BIT - -// constant to convert the fraction bits to cel*(10^-4) -#define DS18X20_FRACCONV 625 - -// scratchpad size in bytes -#define DS18X20_SP_SIZE 9 - -// DS18X20 EEPROM-Support -#define DS18X20_WRITE_SCRATCHPAD 0x4E -#define DS18X20_COPY_SCRATCHPAD 0x48 -#define DS18X20_RECALL_E2 0xB8 -#define DS18X20_COPYSP_DELAY 10 /* ms */ -#define DS18X20_TH_REG 2 -#define DS18X20_TL_REG 3 - -#define DS18X20_DECIMAL_CHAR '.' - - -extern uint8_t DS18X20_find_sensor(uint8_t *diff, - uint8_t id[]); -extern uint8_t DS18X20_get_power_status(uint8_t id[]); -extern uint8_t DS18X20_start_meas( uint8_t with_external, - uint8_t id[]); -// returns 1 if conversion is in progress, 0 if finished -// not available when parasite powered -extern uint8_t DS18X20_conversion_in_progress(void); - - -#if DS18X20_DECICELSIUS -extern uint8_t DS18X20_read_decicelsius( uint8_t id[], - int16_t *decicelsius ); -extern uint8_t DS18X20_read_decicelsius_single( uint8_t familycode, - int16_t *decicelsius ); -extern uint8_t DS18X20_format_from_decicelsius( int16_t decicelsius, - char s[], uint8_t n); -#endif /* DS18X20_DECICELSIUS */ - - -#if DS18X20_MAX_RESOLUTION -// temperature unit for max. resolution is �C * 10e-4 -// examples: -250625 -> -25.0625�C, 1250000 -> 125.0000 �C -extern uint8_t DS18X20_read_maxres( uint8_t id[], - int32_t *temperaturevalue ); -extern uint8_t DS18X20_read_maxres_single( uint8_t familycode, - int32_t *temperaturevalue ); -extern uint8_t DS18X20_format_from_maxres( int32_t temperaturevalue, - char s[], uint8_t n); -#endif /* DS18X20_MAX_RESOLUTION */ - - -#if DS18X20_EEPROMSUPPORT -// write th, tl and config-register to scratchpad (config ignored on DS18S20) -uint8_t DS18X20_write_scratchpad( uint8_t id[], - uint8_t th, uint8_t tl, uint8_t conf); -// read scratchpad into array SP -uint8_t DS18X20_read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n); -// copy values int scratchpad into DS18x20 eeprom -uint8_t DS18X20_scratchpad_to_eeprom( uint8_t with_power_extern, - uint8_t id[] ); -// copy values from DS18x20 eeprom into scratchpad -uint8_t DS18X20_eeprom_to_scratchpad( uint8_t id[] ); -#endif /* DS18X20_EEPROMSUPPORT */ - - -#if DS18X20_VERBOSE -extern void DS18X20_show_id_uart( uint8_t *id, size_t n ); -extern uint8_t DS18X20_read_meas_all_verbose( void ); -#endif /* DS18X20_VERBOSE */ - - -#ifdef __cplusplus -} -#endif - -#endif
--- a/main.c Sun Mar 30 20:20:30 2014 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1200 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <stdbool.h> -#include <stdlib.h> -#include <avr/io.h> -#include <avr/interrupt.h> -#include <avr/sleep.h> -#include <util/delay.h> -#include <avr/pgmspace.h> -#include <avr/eeprom.h> -#include <avr/wdt.h> -#include <util/atomic.h> -#include <util/crc16.h> - -#include "simple_ds18b20.h" -#include "onewire.h" - -// configuration params -// - measurement interval -// - transmit interval -// - bluetooth params -// - number of sensors (and range?) - -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) -#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) - -// TICK should be 8 or less (8 untested). all timers need -// to be a multiple. - -#define TICK 6 -// we have 1024 prescaler, 32768 crystal. -#define SLEEP_COMPARE (32*TICK-1) - -#define VALUE_NOSENSOR 0x07D0 // 125 degrees -#define VALUE_BROKEN 0x07D1 // 125.0625 - -#define OVERSHOOT_MAX_DIV 1800.0 // 30 mins -#define WORT_INVALID_TIME 900 // 15 mins -// fridge min/max are only used if the wort sensor is invalid -#define FRIDGE_AIR_MIN_RANGE 40 // 4º -#define FRIDGE_AIR_MAX_RANGE 40 // 4º - -#define BAUD 19200 -#define UBRR ((F_CPU)/8/(BAUD)-1) - -#define PORT_LED PORTC -#define DDR_LED DDRC -#define PIN_LED PC4 - -#define PORT_SHDN PORTD -#define DDR_SHDN DDRD -#define PIN_SHDN PD7 - -#define PORT_FRIDGE PORTD -#define DDR_FRIDGE DDRD -#define PIN_FRIDGE PD6 - -// total amount of 16bit values available for measurements. -// adjust emperically, be sure to allow enough stack space too -#define TOTAL_MEASUREMENTS 800 - -// each sensor slot uses 8 bytes -#define MAX_SENSORS 6 - -// fixed at 8, have a shorter name -#define ID_LEN OW_ROMCODE_SIZE - -// #define HAVE_UART_ECHO - -// stores a value of clock_epoch combined with the remainder of TCNT2, -// for 1/32 second accuracy -struct epoch_ticks -{ - uint32_t ticks; - // remainder - uint8_t rem; -}; - -// eeprom-settable parameters. all timeouts should -// be a multiple of TICK (6 seconds probably) -static uint16_t measure_wake = 61; // not a divisor of comms_wake -static uint16_t comms_wake = 600; -static uint8_t wake_secs = 30; -// decidegrees -static int16_t fridge_setpoint = 180; // 18.0ºC -static uint16_t fridge_difference = 3; // 0.3ºC -static uint16_t fridge_delay = 600; // seconds - -static uint16_t overshoot_delay = 720; // 12 mins -static uint8_t overshoot_factor = 10; // 1.0ºC - -// ---- Atomic guards required accessing these variables -// clock_epoch in seconds -static uint32_t clock_epoch; -static uint16_t comms_count; -static uint16_t measure_count; -// ---- End atomic guards required - -static uint16_t n_measurements; - -// calculated at startup as TOTAL_MEASUREMENTS/n_sensors -static uint16_t max_measurements; - -static uint16_t measurements[TOTAL_MEASUREMENTS]; - -static struct epoch_ticks first_measurement_clock; -// last_measurement_clock is redundant but checks that we're not missing -// samples -static struct epoch_ticks last_measurement_clock; -static struct epoch_ticks last_comms_clock; - -// boolean flags -static uint8_t need_measurement; -static uint8_t need_comms; -static uint8_t uart_enabled; -static uint8_t stay_awake; -static uint8_t button_pressed; - -// counts down from WAKE_SECS to 0, goes to deep sleep when hits 0 -static uint8_t comms_timeout; - -static uint8_t readpos; -static char readbuf[30]; -static uint8_t have_cmd; - -static uint8_t n_sensors; -static uint8_t sensor_id[MAX_SENSORS][ID_LEN]; - -static int16_t last_fridge = DS18X20_INVALID_DECICELSIUS; -static int16_t last_wort = DS18X20_INVALID_DECICELSIUS; -static struct epoch_ticks fridge_off_clock = {0}; -static struct epoch_ticks fridge_on_clock = {0}; -static struct epoch_ticks wort_valid_clock = {0}; - -int uart_putchar(char c, FILE *stream); -static void long_delay(int ms); -static void blink(); -static uint16_t adc_vcc(); - -static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, - _FDEV_SETUP_WRITE); - -static uint16_t crc_out; -static FILE _crc_stdout = FDEV_SETUP_STREAM(uart_putchar, NULL, - _FDEV_SETUP_WRITE); -// convenience -static FILE *crc_stdout = &_crc_stdout; - - -// thanks to http://projectgus.com/2010/07/eeprom-access-with-arduino/ -#define eeprom_read_to(dst_p, eeprom_field, dst_size) eeprom_read_block((dst_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (dst_size)) -#define eeprom_read(dst, eeprom_field) eeprom_read_to((&dst), eeprom_field, sizeof(dst)) -#define eeprom_write_from(src_p, eeprom_field, src_size) eeprom_write_block((src_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (src_size)) -#define eeprom_write(src, eeprom_field) { eeprom_write_from(&src, eeprom_field, sizeof(src)); } - -#define EXPECT_MAGIC 0x67c9 - -struct __attribute__ ((__packed__)) __eeprom_data { - uint16_t measure_wake; - uint16_t comms_wake; - uint8_t wake_secs; - - int16_t fridge_setpoint; // decidegrees - uint16_t fridge_difference; // decidegrees - uint16_t fridge_delay; - - uint16_t overshoot_delay; - uint8_t overshoot_factor; // decidegrees - -#if 0 - static uint8_t wort_id[ID_LEN]; - static uint8_t fridge_id[ID_LEN]; -#endif - - uint16_t magic; -}; - -static const uint8_t fridge_id[ID_LEN] = - {0x28,0xCE,0xB2,0x1A,0x03,0x00,0x00,0x99}; -static const uint8_t wort_id[ID_LEN] = - {0x28,0x49,0xBC,0x1A,0x03,0x00,0x00,0x54}; - -static void deep_sleep(); - -// 0 or 1 -static uint8_t -is_fridge_on() -{ - if (PORT_FRIDGE & _BV(PIN_FRIDGE)) - { - return 1; - } - else - { - return 0; - } -} - -// Very first setup -static void -setup_chip() -{ - cli(); - - // stop watchdog timer (might have been used to cause a reset) - wdt_reset(); - MCUSR &= ~_BV(WDRF); - WDTCSR |= _BV(WDCE) | _BV(WDE); - WDTCSR = 0; - - // Set clock to 2mhz - CLKPR = _BV(CLKPCE); - // divide by 4 - CLKPR = _BV(CLKPS1); - - // enable pullups - PORTB = 0xff; // XXX change when using SPI - PORTD = 0xff; - PORTC = 0xff; - - // 3.3v power for bluetooth and SD - DDR_LED |= _BV(PIN_LED); - DDR_SHDN |= _BV(PIN_SHDN); - - PORT_FRIDGE &= ~_BV(PIN_FRIDGE); - DDR_FRIDGE |= _BV(PIN_FRIDGE); - - // set pullup - PORTD |= _BV(PD2); - // INT0 setup - EICRA = (1<<ISC01); // falling edge - data sheet says it won't work? - EIMSK = _BV(INT0); - - // comparator disable - ACSR = _BV(ACD); - - // disable adc pin input buffers - DIDR0 = 0x3F; // acd0-adc5 - DIDR1 = (1<<AIN1D)|(1<<AIN0D); // ain0/ain1 - - sei(); -} - -static void -set_aux_power(uint8_t on) -{ - if (on) - { - PORT_SHDN &= ~_BV(PIN_SHDN); - } - else - { - PORT_SHDN |= _BV(PIN_SHDN); - } -} - -static void -get_epoch_ticks(struct epoch_ticks *t) -{ - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - t->ticks = clock_epoch; - t->rem = TCNT2; - } -} - -static void -set_measurement(uint8_t sensor, uint16_t measurement, uint16_t reading) -{ - measurements[sensor*max_measurements + measurement] = reading; -} - -static uint16_t -get_measurement(uint8_t sensor, uint16_t measurement) -{ - return measurements[sensor*max_measurements + measurement]; -} - -static void -setup_tick_counter() -{ - // set up counter2. - // COM21 COM20 Set OC2 on Compare Match (p116) - // WGM21 Clear counter on compare - //TCCR2A = _BV(COM2A1) | _BV(COM2A0) | _BV(WGM21); - // toggle on match - TCCR2A = _BV(COM2A0); - // CS22 CS21 CS20 clk/1024 - TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); - // set async mode - ASSR |= _BV(AS2); - TCNT2 = 0; - OCR2A = SLEEP_COMPARE; - // interrupt - TIMSK2 = _BV(OCIE2A); -} - -static void -uart_on() -{ - // Power reduction register - PRR &= ~_BV(PRUSART0); - - // All of this needs to be done each time after turning off the PRR - // baud rate - UBRR0H = (unsigned char)(UBRR >> 8); - UBRR0L = (unsigned char)UBRR; - // set 2x clock, improves accuracy of UBRR - UCSR0A |= _BV(U2X0); - UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); - //8N1 - UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); - uart_enabled = 1; -} - -static void -uart_off() -{ - // Turn off interrupts and disable tx/rx - UCSR0B = 0; - uart_enabled = 0; - - // Power reduction register - PRR |= _BV(PRUSART0); -} - -int -uart_putchar(char c, FILE *stream) -{ - if (!uart_enabled) - { - return EOF; - } - // XXX could perhaps sleep in the loop for power. - if (c == '\n') - { - loop_until_bit_is_set(UCSR0A, UDRE0); - UDR0 = '\r'; - } - loop_until_bit_is_set(UCSR0A, UDRE0); - UDR0 = c; - if (stream == crc_stdout) - { - crc_out = _crc_ccitt_update(crc_out, c); - } - if (c == '\r') - { - loop_until_bit_is_set(UCSR0A, UDRE0); - UDR0 = '\n'; - if (stream == crc_stdout) - { - crc_out = _crc_ccitt_update(crc_out, '\n'); - } - } - return (unsigned char)c; -} - -static void -cmd_fetch() -{ - crc_out = 0; - - fprintf_P(crc_stdout, PSTR("START\n")); - { - struct epoch_ticks now; - get_epoch_ticks(&now); - fprintf_P(crc_stdout, PSTR("now=%lu\n"), now.ticks); - fprintf_P(crc_stdout, PSTR("now_rem=%hhu\n"), now.rem); - } - fprintf_P(crc_stdout, PSTR("time_step=%hu\n"), measure_wake); - fprintf_P(crc_stdout, PSTR("first_time=%lu\n"), first_measurement_clock.ticks); - fprintf_P(crc_stdout, PSTR("first_time_rem=%hhu\n"), first_measurement_clock.rem); - fprintf_P(crc_stdout, PSTR("last_time=%lu\n"), last_measurement_clock.ticks); - fprintf_P(crc_stdout, PSTR("last_time_rem=%hhu\n"), last_measurement_clock.rem); - fprintf_P(crc_stdout, PSTR("comms_time=%lu\n"), last_comms_clock.ticks); - fprintf_P(crc_stdout, PSTR("comms_time_rem=%hhu\n"), last_comms_clock.rem); - fprintf_P(crc_stdout, PSTR("voltage=%hu\n"), adc_vcc()); - fprintf_P(crc_stdout, PSTR("measure=%hu\n"), measure_wake); - fprintf_P(crc_stdout, PSTR("comms=%hu\n"), comms_wake); - fprintf_P(crc_stdout, PSTR("wake=%hhu\n"), wake_secs); - fprintf_P(crc_stdout, PSTR("fridge=%.1f\n"), fridge_setpoint/10.0); - fprintf_P(crc_stdout, PSTR("fridge_diff=%.1f\n"), fridge_difference/10.0); - fprintf_P(crc_stdout, PSTR("fridge_delay=%hu\n"), fridge_delay); - fprintf_P(crc_stdout, PSTR("overshoot_factor=%.1f\n"), overshoot_factor/10.0); - fprintf_P(crc_stdout, PSTR("overshoot_delay=%hu\n"), overshoot_delay); - fprintf_P(crc_stdout, PSTR("fridge_status=%hhu\n"), is_fridge_on()); - fprintf_P(crc_stdout, PSTR("fridge_last_on=%lu\n"), fridge_on_clock.ticks); - fprintf_P(crc_stdout, PSTR("fridge_last_off=%lu\n"), fridge_off_clock.ticks); - fprintf_P(crc_stdout, PSTR("last_fridge=%hu\n"), last_fridge); - fprintf_P(crc_stdout, PSTR("last_wort=%hu\n"), last_wort); - fprintf_P(crc_stdout, PSTR("tick_secs=%d\n"), TICK); - fprintf_P(crc_stdout, PSTR("tick_wake=%d\n"), SLEEP_COMPARE); - fprintf_P(crc_stdout, PSTR("maxsens=%hhu\n"), MAX_SENSORS); - fprintf_P(crc_stdout, PSTR("totalmeas=%hu\n"), TOTAL_MEASUREMENTS); - fprintf_P(crc_stdout, PSTR("sensors=%hhu\n"), n_sensors); - for (uint8_t s = 0; s < n_sensors; s++) - { - fprintf_P(crc_stdout, PSTR("sensor_id%hhu="), s); - printhex(sensor_id[s], ID_LEN, crc_stdout); - fputc('\n', crc_stdout); - } - fprintf_P(crc_stdout, PSTR("measurements=%hu\n"), n_measurements); - for (uint16_t n = 0; n < n_measurements; n++) - { - fprintf_P(crc_stdout, PSTR("meas%hu="), n); - for (uint8_t s = 0; s < n_sensors; s++) - { - fprintf_P(crc_stdout, PSTR(" %04hx"), get_measurement(s, n)); - } - fputc('\n', crc_stdout); - } - fprintf_P(crc_stdout, PSTR("END\n")); - fprintf_P(stdout, PSTR("CRC=%hu\n"), crc_out); -} - -static void -cmd_clear() -{ - n_measurements = 0; - printf_P(PSTR("cleared\n")); -} - -static void -cmd_btoff() -{ - uint8_t rem; - uint16_t count_copy; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - count_copy = comms_count; - rem = TCNT2; - } - printf_P(PSTR("next_wake=%hu,"), comms_wake-count_copy); - printf_P(PSTR("rem=%hhu,"), rem); - printf_P(PSTR("tick_secs=%hhu,"), TICK); - printf_P(PSTR("tick_wake=%hhu\n"), SLEEP_COMPARE); - _delay_ms(100); - comms_timeout = 0; - stay_awake = 0; -} - -static void -cmd_reset() -{ - printf_P(PSTR("reset\n")); - _delay_ms(100); - cli(); // disable interrupts - wdt_enable(WDTO_15MS); // enable watchdog - while(1); // wait for watchdog to reset processor -} - -static void -cmd_measure() -{ - printf_P(PSTR("measuring\n")); - need_measurement = 1; -} - -static void -cmd_sensors() -{ - uint8_t ret = simple_ds18b20_start_meas(NULL); - printf_P(PSTR("All sensors, ret %hhu, waiting...\n"), ret); - long_delay(DS18B20_TCONV_12BIT); - simple_ds18b20_read_all(); -} - -static void -init_sensors() -{ - uint8_t id[OW_ROMCODE_SIZE]; - printf_P(PSTR("init sensors\n")); - ow_reset(); - for( uint8_t diff = OW_SEARCH_FIRST; diff != OW_LAST_DEVICE; ) - { - diff = ow_rom_search( diff, &id[0] ); - if( diff == OW_PRESENCE_ERR ) { - printf_P( PSTR("No Sensor found\r") ); - return; - } - - if( diff == OW_DATA_ERR ) { - printf_P( PSTR("Bus Error\r") ); - return; - } - - if (n_sensors < MAX_SENSORS) - { - memcpy(sensor_id[n_sensors], id, ID_LEN); - printf_P(PSTR("Added sensor %hhu : "), n_sensors); - printhex(id, ID_LEN, stdout); - putchar('\n'); - n_sensors++; - } - else - { - printf_P(PSTR("Too many sensors\n")); - } - } - - max_measurements = TOTAL_MEASUREMENTS / n_sensors; -} - -static void -load_params() -{ - uint16_t magic; - eeprom_read(magic, magic); - if (magic == EXPECT_MAGIC) - { - eeprom_read(measure_wake, measure_wake); - eeprom_read(comms_wake, comms_wake); - eeprom_read(wake_secs, wake_secs); - eeprom_read(fridge_setpoint, fridge_setpoint); - eeprom_read(fridge_difference, fridge_difference); - eeprom_read(fridge_delay, fridge_delay); - eeprom_read(overshoot_delay, overshoot_delay); - eeprom_read(overshoot_factor, overshoot_factor); - } -} - -static void -cmd_get_params() -{ - printf_P(PSTR("measure %hu\n"), measure_wake); - printf_P(PSTR("comms %hu\n"), comms_wake); - printf_P(PSTR("wake %hhu\n"), wake_secs); - printf_P(PSTR("tick %d\n"), TICK); - printf_P(PSTR("fridge %.1fº\n"), fridge_setpoint / 10.0f); - printf_P(PSTR("fridge difference %.1fº\n"), fridge_difference / 10.0f); - printf_P(PSTR("fridge_delay %hu\n"), fridge_delay); - printf_P(PSTR("overshoot factor %.1fº\n"), overshoot_factor / 10.0f); - printf_P(PSTR("overshoot delay %hu\n"), overshoot_delay); - printf_P(PSTR("sensors %hhu (%hhu)\n"), - n_sensors, MAX_SENSORS); - printf_P(PSTR("meas %hu (%hu)\n"), - max_measurements, TOTAL_MEASUREMENTS); -} - -static void -cmd_set_params(const char *params) -{ - uint16_t new_measure_wake; - uint16_t new_comms_wake; - uint8_t new_wake_secs; - int ret = sscanf_P(params, PSTR("%hu %hu %hhu"), - &new_measure_wake, &new_comms_wake, &new_wake_secs); - - if (ret != 3) - { - printf_P(PSTR("Bad values\n")); - } - else - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - eeprom_write(new_measure_wake, measure_wake); - eeprom_write(new_comms_wake, comms_wake); - eeprom_write(new_wake_secs, wake_secs); - uint16_t magic = EXPECT_MAGIC; - eeprom_write(magic, magic); - } - printf_P(PSTR("set_params for next boot\n")); - printf_P(PSTR("measure %hu comms %hu wake %hhu\n"), - new_measure_wake, new_comms_wake, new_wake_secs); - } -} - -// returns true if eeprom was written -static bool -set_initial_eeprom() -{ - uint16_t magic; - eeprom_read(magic, magic); - if (magic == EXPECT_MAGIC) - { - return false; - } - - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - eeprom_write(measure_wake, measure_wake); - eeprom_write(comms_wake, comms_wake); - eeprom_write(wake_secs, wake_secs); - eeprom_write(fridge_setpoint, fridge_setpoint); - eeprom_write(fridge_difference, fridge_difference); - eeprom_write(fridge_delay, fridge_delay); - eeprom_write(overshoot_delay, overshoot_delay); - eeprom_write(overshoot_factor, overshoot_factor); - magic = EXPECT_MAGIC; - eeprom_write(magic, magic); - } - - return true; -} - -static void -cmd_set_fridge_setpoint(char *params) -{ - float new_f = atof(params); - if (new_f < 2 || new_f > 30) - { - printf_P(PSTR("Bad fridge value %f\n"), new_f); - return; - } - - int16_t old_setpoint = fridge_setpoint; - - fridge_setpoint = new_f * 10; - bool written = set_initial_eeprom(); - if (!written) - { - if (old_setpoint != fridge_setpoint) - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - eeprom_write(fridge_setpoint, fridge_setpoint); - } - } - } - printf_P(PSTR("old fridge %.1fº new fridge %.1fº\n"), - old_setpoint / 10.0f, fridge_setpoint / 10.0f); -} - -static void -cmd_set_fridge_difference(char *params) -{ - float new_f = atof(params); - if (new_f < 0 || new_f > 30) - { - printf_P(PSTR("Bad fridge value %f\n"), new_f); - return; - } - - fridge_difference = new_f * 10; - bool written = set_initial_eeprom(); - if (!written) - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - eeprom_write(fridge_difference, fridge_difference); - } - } - printf_P(PSTR("new fridge difference %.1fº\n"), fridge_difference / 10.0f); -} - -static void -cmd_set_fridge_delay(char *params) -{ - uint16_t new_delay = atoi(params); - if (new_delay < 5) - { - printf_P(PSTR("Bad fridge delay %d\n"), new_delay); - return; - } - - fridge_delay = new_delay; - bool written = set_initial_eeprom(); - if (!written) - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - eeprom_write(fridge_delay, fridge_delay); - } - } - printf_P(PSTR("new fridge delay %hu\n"), fridge_delay); -} - -static void -cmd_set_overshoot_factor(char *params) -{ - float new_f = atof(params); - if (new_f <= 0 || new_f > 20) - { - printf_P(PSTR("Bad overshoot factor %f\n"), new_f); - return; - } - - uint8_t old = overshoot_factor; - - overshoot_factor = new_f * 10; - bool written = set_initial_eeprom(); - if (!written) - { - if (old != overshoot_factor) - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - eeprom_write(overshoot_factor, overshoot_factor); - } - } - } - printf_P(PSTR("old factor %.1fº new factor %.1fº\n"), - old / 10.0f, overshoot_factor / 10.0f); -} - -static void -cmd_set_overshoot_delay(char *params) -{ - uint16_t new_delay = atoi(params); - if (new_delay < 5) - { - printf_P(PSTR("Bad overshoot delay %d\n"), new_delay); - return; - } - - overshoot_delay = new_delay; - bool written = set_initial_eeprom(); - if (!written) - { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - eeprom_write(overshoot_delay, overshoot_delay); - } - } - printf_P(PSTR("new overshoot delay %hu\n"), overshoot_delay); -} - -static void -cmd_awake() -{ - stay_awake = 1; - printf_P(PSTR("awake\n")); -} - -static void -read_handler() -{ - if (strcmp_P(readbuf, PSTR("fetch")) == 0) - { - cmd_fetch(); - } - else if (strcmp_P(readbuf, PSTR("clear")) == 0) - { - cmd_clear(); - } - else if (strcmp_P(readbuf, PSTR("btoff")) == 0) - { - cmd_btoff(); - } - else if (strcmp_P(readbuf, PSTR("measure")) == 0) - { - cmd_measure(); - } - else if (strcmp_P(readbuf, PSTR("sensors")) == 0) - { - cmd_sensors(); - } - else if (strcmp_P(readbuf, PSTR("get_params")) == 0) - { - cmd_get_params(); - } - else if (strncmp_P(readbuf, PSTR("set_params "), 11) == 0) - { - cmd_set_params(&readbuf[11]); - } - else if (strcmp_P(readbuf, PSTR("awake")) == 0) - { - cmd_awake(); - } - else if (strncmp_P(readbuf, PSTR("fridge_setpoint "), 16) == 0) - { - cmd_set_fridge_setpoint(&readbuf[16]); - } - else if (strncmp_P(readbuf, PSTR("fridge_diff "), 12) == 0) - { - cmd_set_fridge_difference(&readbuf[12]); - } - else if (strncmp_P(readbuf, PSTR("fridge_delay "), 13) == 0) - { - cmd_set_fridge_delay(&readbuf[13]); - } - else if (strncmp_P(readbuf, PSTR("overshoot_delay "), 16) == 0) - { - cmd_set_overshoot_delay(&readbuf[16]); - } - else if (strncmp_P(readbuf, PSTR("overshoot_factor "), 17) == 0) - { - cmd_set_overshoot_factor(&readbuf[17]); - } - else if (strcmp_P(readbuf, PSTR("reset")) == 0) - { - cmd_reset(); - } - else - { - printf_P(PSTR("Bad command '%s'\n"), readbuf); - } -} - -ISR(INT0_vect) -{ - button_pressed = 1; - blink(); - _delay_ms(100); - blink(); -} - - -ISR(USART_RX_vect) -{ - char c = UDR0; -#ifdef HAVE_UART_ECHO - uart_putchar(c, NULL); -#endif - if (c == '\r' || c == '\n') - { - if (readpos > 0) - { - readbuf[readpos] = '\0'; - have_cmd = 1; - readpos = 0; - } - } - else - { - readbuf[readpos] = c; - readpos++; - if (readpos >= sizeof(readbuf)) - { - readpos = 0; - } - } -} - -ISR(TIMER2_COMPA_vect) -{ - TCNT2 = 0; - measure_count += TICK; - comms_count += TICK; - - clock_epoch += TICK; - - if (comms_timeout != 0) - { - comms_timeout -= TICK; - } - - if (measure_count >= measure_wake) - { - measure_count = 0; - need_measurement = 1; - } - - if (comms_count >= comms_wake) - { - comms_count = 0; - need_comms = 1; - } -} - -static void -deep_sleep() -{ - // p119 of manual - OCR2A = SLEEP_COMPARE; - loop_until_bit_is_clear(ASSR, OCR2AUB); - - set_sleep_mode(SLEEP_MODE_PWR_SAVE); - sleep_mode(); -} - -static void -idle_sleep() -{ - set_sleep_mode(SLEEP_MODE_IDLE); - sleep_mode(); -} - -static uint16_t -adc_vcc() -{ - PRR &= ~_BV(PRADC); - - // /16 prescaler - ADCSRA = _BV(ADEN) | _BV(ADPS2); - - // set to measure 1.1 reference - ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); - // average a number of samples