changeset 0:8705acff2494

lots of stuff
author Matt Johnston <matt@ucc.asn.au>
date Sat, 01 Jun 2013 01:38:42 +0800
parents
children e23c1b6f6080
files Makefile cli.h config.h crc8.c crc8.h debug.h ds18x20.h hmac-sha1.c hmac-sha1.h main.c onewire.c onewire.h sha1-asm.S sha1.c sha1.h simple_ds18b20.c simple_ds18b20.h
diffstat 15 files changed, 3563 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,114 @@
+# 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_CRYPTO = sha1.c hmac-sha1.c sha1-asm.S
+SOURCE    = main.c
+SOURCE += $(SOURCE_1WIRE) $(SOURCE_CRYPTO)
+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 -fwhole-program  -Wl,-u,vfprintf -lprintf_flt -lm
+COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -g -std=c99 -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc8.c	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,63 @@
+/* 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.
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crc8.h	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,40 @@
+#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.
+*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debug.h	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,1 @@
+#define DEBUG_S(x)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ds18x20.h	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,140 @@
+#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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hmac-sha1.c	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,131 @@
+/* hmac-sha1.c */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2008  Daniel Otte ([email protected])
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * 
+ * implementation of HMAC as described in RFC2104
+ * Author:      Daniel Otte
+ * email:       [email protected]
+ * License:     GPLv3 or later
+ **/
+
+/* 
+ * hmac = hash ( k^opad , hash( k^ipad  , msg))
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "config.h"
+#include "sha1.h"
+#include "hmac-sha1.h"
+
+#define IPAD 0x36
+#define OPAD 0x5C
+
+
+#ifndef HMAC_SHORTONLY
+
+void hmac_sha1_init(hmac_sha1_ctx_t *s, const void* key, uint16_t keylength_b){
+	uint8_t buffer[SHA1_BLOCK_BYTES];
+	uint8_t i;
+	
+	memset(buffer, 0, SHA1_BLOCK_BYTES);
+	if (keylength_b > SHA1_BLOCK_BITS){
+		sha1((void*)buffer, key, keylength_b);
+	} else {
+		memcpy(buffer, key, (keylength_b+7)/8);
+	}
+	
+	for (i=0; i<SHA1_BLOCK_BYTES; ++i){
+		buffer[i] ^= IPAD;
+	}
+	sha1_init(&(s->a));
+	sha1_nextBlock(&(s->a), buffer);
+	
+	for (i=0; i<SHA1_BLOCK_BYTES; ++i){
+		buffer[i] ^= IPAD^OPAD;
+	}
+	sha1_init(&(s->b));
+	sha1_nextBlock(&(s->b), buffer);
+	
+	
+#if defined SECURE_WIPE_BUFFER
+	memset(buffer, 0, SHA1_BLOCK_BYTES);
+#endif
+}
+
+void hmac_sha1_nextBlock(hmac_sha1_ctx_t *s, const void* block){
+	sha1_nextBlock(&(s->a), block);
+}
+void hmac_sha1_lastBlock(hmac_sha1_ctx_t *s, const void* block, uint16_t length_b){
+	while(length_b>=SHA1_BLOCK_BITS){
+		sha1_nextBlock(&s->a, block);
+		block = (uint8_t*)block + SHA1_BLOCK_BYTES;
+		length_b -= SHA1_BLOCK_BITS;
+	}
+	sha1_lastBlock(&s->a, block, length_b);
+}
+
+void hmac_sha1_final(void* dest, hmac_sha1_ctx_t *s){
+	sha1_ctx2hash(dest, &s->a);
+	sha1_lastBlock(&s->b, dest, SHA1_HASH_BITS);
+	sha1_ctx2hash(dest, &(s->b));
+}
+
+#endif
+
+/*
+ * keylength in bits!
+ * message length in bits!
+ */
+void hmac_sha1(void* dest, const void* key, uint16_t keylength_b, const void* msg, uint32_t msglength_b){ /* a one-shot*/
+	sha1_ctx_t s;
+	uint8_t i;
+	uint8_t buffer[SHA1_BLOCK_BYTES];
+	
+	memset(buffer, 0, SHA1_BLOCK_BYTES);
+	
+	/* if key is larger than a block we have to hash it*/
+	if (keylength_b > SHA1_BLOCK_BITS){
+		sha1((void*)buffer, key, keylength_b);
+	} else {
+		memcpy(buffer, key, (keylength_b+7)/8);
+	}
+	
+	for (i=0; i<SHA1_BLOCK_BYTES; ++i){
+		buffer[i] ^= IPAD;
+	}
+	sha1_init(&s);
+	sha1_nextBlock(&s, buffer);
+	while (msglength_b >= SHA1_BLOCK_BITS){
+		sha1_nextBlock(&s, msg);
+		msg = (uint8_t*)msg + SHA1_BLOCK_BYTES;
+		msglength_b -=  SHA1_BLOCK_BITS;
+	}
+	sha1_lastBlock(&s, msg, msglength_b);
+	/* since buffer still contains key xor ipad we can do ... */
+	for (i=0; i<SHA1_BLOCK_BYTES; ++i){
+		buffer[i] ^= IPAD ^ OPAD;
+	}
+	sha1_ctx2hash(dest, &s); /* save inner hash temporary to dest */
+	sha1_init(&s);
+	sha1_nextBlock(&s, buffer);
+	sha1_lastBlock(&s, dest, SHA1_HASH_BITS);
+	sha1_ctx2hash(dest, &s);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hmac-sha1.h	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,41 @@
+/* hmac-sha1.h */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2008  Daniel Otte ([email protected])
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef HMACSHA1_H_
+#define HMACSHA1_H_
+
+#include "sha1.h"
+
+#define HMAC_SHA1_BITS        SHA1_HASH_BITS
+#define HMAC_SHA1_BYTES       SHA1_HASH_BYTES
+#define HMAC_SHA1_BLOCK_BITS  SHA1_BLOCK_BITS
+#define HMAC_SHA1_BLOCK_BYTES SHA1_BLOCK_BYTES
+
+typedef struct{
+	 sha1_ctx_t a, b;
+} hmac_sha1_ctx_t;
+
+
+void hmac_sha1_init(hmac_sha1_ctx_t *s, const void* key, uint16_t keylength_b);
+void hmac_sha1_nextBlock(hmac_sha1_ctx_t *s, const void* block);
+void hmac_sha1_lastBlock(hmac_sha1_ctx_t *s, const void* block, uint16_t length_b);
+void hmac_sha1_final(void* dest, hmac_sha1_ctx_t *s);
+
+void hmac_sha1(void* dest, const void* key, uint16_t keylength_b, const void* msg, uint32_t msglength_b);
+
+#endif /*HMACSHA1_H_*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.c	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,1200 @@
+#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
+    uint16_t sum = 0;
+    uint8_t num = 0;
+    for (uint8_t n = 0; n < 20; n++)
+    {
+        ADCSRA |= _BV(ADSC);
+        loop_until_bit_is_clear(ADCSRA, ADSC);
+
+        uint8_t low_11 = ADCL;
+        uint8_t high_11 = ADCH;
+        uint16_t val = low_11 + (high_11 << 8);
+
+        if (n >= 4)
+        {
+            sum += val;
+            num++;
+        }
+    }
+    ADCSRA = 0;
+    PRR |= _BV(PRADC);
+
+    //float res_volts = 1.1 * 1024 * num / sum;
+    //return 1000 * res_volts;
+    return ((uint32_t)1100*1024*num) / sum;
+}
+
+static void
+do_fridge()
+{
+    struct epoch_ticks now;
+    get_epoch_ticks(&now);
+    uint32_t off_time = now.ticks - fridge_off_clock.ticks;
+    bool wort_valid = last_wort != DS18X20_INVALID_DECICELSIUS;
+    bool fridge_valid = last_fridge != DS18X20_INVALID_DECICELSIUS;
+
+    int16_t wort_max = fridge_setpoint + fridge_difference;
+    int16_t wort_min = fridge_setpoint;
+
+    // the fridge min/max only apply if the wort sensor is broken
+    int16_t fridge_min = fridge_setpoint - FRIDGE_AIR_MIN_RANGE;
+    int16_t fridge_max = fridge_setpoint + FRIDGE_AIR_MAX_RANGE;
+
+    uint8_t fridge_on = PORT_FRIDGE & _BV(PIN_FRIDGE);
+    printf_P(PSTR("last_wort %hd (%hd, %hd), last_fridge %hd (%hd, %hd), setpoint %hd, diff %hd, fridge_on %hhu\n"), 
+            last_wort, wort_min, wort_max, 
+            last_fridge, fridge_min, fridge_max, 
+            fridge_setpoint, fridge_difference, fridge_on);
+
+    if (off_time < fridge_delay)
+    {
+        printf_P(PSTR("waiting for fridge delay current %hu, wait %hu\n"),
+                off_time, fridge_delay);
+        return;
+    }
+
+    // handle failure of the wort sensor. if it is a short (intermittent?)
+    // failure we wait until it has been broken for a period of time
+    // (WORT_INVALID_TIME) before doing anything.
+    if (wort_valid)
+    {
+        wort_valid_clock = now;
+    }
+    else
+    {
+        printf_P(PSTR("wort sensor is invalid\n"));
+        uint32_t invalid_time = now.ticks - wort_valid_clock.ticks;
+        if (invalid_time < WORT_INVALID_TIME)
+        {
+            printf("only been invalid for %ld, waiting\n", invalid_time);
+            return;
+        }
+    }
+
+    if (!fridge_valid)
+    {
+        printf_P(PSTR("fridge sensor is invalid\n"));
+    }
+
+    if (fridge_on)
+    {
+        bool turn_off = false;
+        uint16_t on_time = now.ticks - fridge_on_clock.ticks;
+
+        uint16_t overshoot = 0;
+        if (on_time > overshoot_delay)
+        {
+            overshoot = overshoot_factor * MIN(OVERSHOOT_MAX_DIV, on_time) / OVERSHOOT_MAX_DIV;
+        }
+
+        printf_P(PSTR("on_time %hu, overshoot %hu\n"), on_time, overshoot);
+
+        // wort has cooled enough. will probably cool a bit more by itself
+        if (wort_valid)
+        {
+            if ((last_wort - overshoot) < fridge_setpoint)
+            {
+                printf_P(PSTR("wort has cooled enough, overshoot %hu on_time %hu\n"), overshoot, on_time);
+                turn_off = true;
+            }
+        }
+        else
+        {
+            if (fridge_valid && last_fridge < fridge_min)
+            {
+                printf_P(PSTR("fridge off fallback\n"));
+                turn_off = true;
+            }
+        }
+
+        if (turn_off)
+        {
+            // too cold, turn off
+            printf_P(PSTR("Turning fridge off\n"));
+            PORT_FRIDGE &= ~_BV(PIN_FRIDGE);
+            fridge_off_clock = now;
+        }
+    }
+    else
+    {
+        bool turn_on = false;
+
+        if (wort_valid)
+        {
+            if (last_wort >= wort_max)
+            {
+                printf_P(PSTR("wort is too hot\n"));
+                turn_on = true;
+            }
+        }
+        else
+        {
+            if (fridge_valid && last_fridge >= fridge_max)
+            {
+                printf_P(PSTR("fridge on fallback\n"));
+                turn_on = true;
+            }
+        }
+
+        if (turn_on)
+        {
+            // too hot, turn on
+            printf_P(PSTR("Turning fridge on\n"));
+            PORT_FRIDGE |= _BV(PIN_FRIDGE);
+            fridge_on_clock = now;
+        }
+    }
+}
+
+static void
+do_measurement()
+{
+    blink();
+
+    /* Take the timer here since deep_sleep() below could take 6 seconds */
+    get_epoch_ticks(&last_measurement_clock);
+    if (n_measurements == 0)
+    {
+        first_measurement_clock = last_measurement_clock;
+    }
+
+    simple_ds18b20_start_meas(NULL);
+    _delay_ms(DS18B20_TCONV_12BIT);
+
+    if (n_measurements == max_measurements)
+    {
+        n_measurements = 0;
+    }
+
+    for (uint8_t s = 0; s < n_sensors; s++)
+    {
+        uint16_t reading;
+        uint8_t ret = simple_ds18b20_read_raw(sensor_id[s], &reading);
+        if (ret != DS18X20_OK)
+        {
+            reading = VALUE_BROKEN;
+        }
+        set_measurement(s, n_measurements, reading);
+
+        if (memcmp(sensor_id[s], fridge_id, sizeof(fridge_id)) == 0)
+        {
+            last_fridge = ds18b20_raw16_to_decicelsius(reading);
+        }
+        if (memcmp(sensor_id[s], wort_id, sizeof(wort_id)) == 0)
+        {
+            last_wort = ds18b20_raw16_to_decicelsius(reading);
+        }
+    }
+
+    n_measurements++;
+}
+
+static void
+do_comms()
+{
+    get_epoch_ticks(&last_comms_clock);
+
+    // turn on bluetooth
+    set_aux_power(1);
+    // avoid receiving rubbish, perhaps
+    _delay_ms(50);
+    uart_on();
+    
+    // write sd card here? same 3.3v regulator...
+    
+    for (comms_timeout = wake_secs; 
+        comms_timeout > 0 || stay_awake;  
+        )
+    {
+        if (need_measurement)
+        {
+            need_measurement = 0;
+            do_measurement();
+            do_fridge();
+            continue;
+        }
+
+        if (have_cmd)
+        {
+            have_cmd = 0;
+            read_handler();
+            continue;
+        }
+
+        // wait for commands from the master
+        idle_sleep();
+    }
+
+    uart_off();
+    // in case bluetooth takes time to flush
+    _delay_ms(100);
+    set_aux_power(0);
+}
+
+static void
+blink()
+{
+    PORT_LED &= ~_BV(PIN_LED);
+    _delay_ms(1);
+    PORT_LED |= _BV(PIN_LED);
+}
+
+static void
+long_delay(int ms)
+{
+    int iter = ms / 100;
+
+    for (int i = 0; i < iter; i++)
+    {
+        _delay_ms(100);
+    }
+}
+
+ISR(BADISR_vect)
+{
+    //uart_on();
+    printf_P(PSTR("Bad interrupt\n"));
+}
+
+int main(void)
+{
+    setup_chip();
+    blink();
+
+    set_aux_power(0);
+
+    stdout = &mystdout;
+    uart_on();
+
+    printf(PSTR("Started.\n"));
+
+    load_params();
+
+    init_sensors();
+
+    uart_off();
+
+    // turn off everything except timer2
+    PRR = _BV(PRTWI) | _BV(PRTIM0) | _BV(PRTIM1) | _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC);
+
+    setup_tick_counter();
+
+    sei();
+
+    need_comms = 1;
+    need_measurement = 1;
+
+    stay_awake = 1;
+
+    for(;;)
+    {
+        if (button_pressed)
+        {
+            // debounce
+            _delay_ms(200);
+            need_comms = 1;
+            comms_timeout = wake_secs;
+            button_pressed = 0;
+            continue;
+        }
+
+        if (need_comms)
+        {
+            need_comms = 0;
+            do_comms();
+            continue;
+        }
+
+        if (need_measurement)
+        {
+            need_measurement = 0;
+            do_measurement();
+            do_fridge();
+            continue;
+        }
+
+        deep_sleep();
+    }
+
+    return 0;   /* never reached */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onewire.c	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,287 @@
+/* 
+Access Dallas 1-Wire Devices with ATMEL AVRs
+Author of the initial code: Peter Dannegger (danni(at)specs.de)
+modified by Martin Thomas (mthomas(at)rhrk.uni-kl.de)
+ 9/2004 - use of delay.h, optional bus configuration at runtime
+10/2009 - additional delay in ow_bit_io for recovery
+ 5/2010 - timing modifcations, additonal config-values and comments,
+          use of atomic.h macros, internal pull-up support
+ 7/2010 - added method to skip recovery time after last bit transfered
+          via ow_command_skip_last_recovery
+*/
+
+
+#include <avr/io.h>
+#include <util/delay.h>
+#include <util/atomic.h>
+
+#include "onewire.h"
+
+#ifdef OW_ONE_BUS
+
+#define OW_GET_IN()   ( OW_IN & (1<<OW_PIN))
+#define OW_OUT_LOW()  ( OW_OUT &= (~(1 << OW_PIN)) )
+#define OW_OUT_HIGH() ( OW_OUT |= (1 << OW_PIN) )
+#define OW_DIR_IN()   ( OW_DDR &= (~(1 << OW_PIN )) )
+#define OW_DIR_OUT()  ( OW_DDR |= (1 << OW_PIN) )
+
+#else
+
+/* set bus-config with ow_set_bus() */
+uint8_t OW_PIN_MASK; 
+volatile uint8_t* OW_IN;
+volatile uint8_t* OW_OUT;
+volatile uint8_t* OW_DDR;
+
+#define OW_GET_IN()   ( *OW_IN & OW_PIN_MASK )
+#define OW_OUT_LOW()  ( *OW_OUT &= (uint8_t) ~OW_PIN_MASK )
+#define OW_OUT_HIGH() ( *OW_OUT |= (uint8_t)  OW_PIN_MASK )
+#define OW_DIR_IN()   ( *OW_DDR &= (uint8_t) ~OW_PIN_MASK )
+#define OW_DIR_OUT()  ( *OW_DDR |= (uint8_t)  OW_PIN_MASK )
+
+void ow_set_bus(volatile uint8_t* in,
+	volatile uint8_t* out,
+	volatile uint8_t* ddr,
+	uint8_t pin)
+{
+	OW_DDR=ddr;
+	OW_OUT=out;
+	OW_IN=in;
+	OW_PIN_MASK = (1 << pin);
+	ow_reset();
+}
+
+#endif
+
+uint8_t ow_input_pin_state()
+{
+	return OW_GET_IN();
+}
+
+void ow_parasite_enable(void)
+{
+	OW_OUT_HIGH();
+	OW_DIR_OUT();
+}
+
+void ow_parasite_disable(void)
+{
+	OW_DIR_IN();
+#if (!OW_USE_INTERNAL_PULLUP)
+	OW_OUT_LOW();
+#endif
+}
+
+
+uint8_t ow_reset(void)
+{
+	uint8_t err;
+	
+	OW_OUT_LOW();
+	OW_DIR_OUT();            // pull OW-Pin low for 480us
+	_delay_us(480);
+
+	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+		// set Pin as input - wait for clients to pull low
+		OW_DIR_IN(); // input
+#if OW_USE_INTERNAL_PULLUP
+		OW_OUT_HIGH();
+#endif
+	
+		_delay_us(64);       // was 66
+		err = OW_GET_IN();   // no presence detect
+		                     // if err!=0: nobody pulled to low, still high
+	}
+	
+	// after a delay the clients should release the line
+	// and input-pin gets back to high by pull-up-resistor
+	_delay_us(480 - 64);       // was 480-66
+	if( OW_GET_IN() == 0 ) {
+		err = 1;             // short circuit, expected low but got high
+	}
+	
+	return err;
+}
+
+
+/* Timing issue when using runtime-bus-selection (!OW_ONE_BUS):
+   The master should sample at the end of the 15-slot after initiating
+   the read-time-slot. The variable bus-settings need more
+   cycles than the constant ones so the delays had to be shortened 
+   to achive a 15uS overall delay 
+   Setting/clearing a bit in I/O Register needs 1 cyle in OW_ONE_BUS
+   but around 14 cyles in configureable bus (us-Delay is 4 cyles per uS) */
+static uint8_t ow_bit_io_intern( uint8_t b, uint8_t with_parasite_enable )
+{
+	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+#if OW_USE_INTERNAL_PULLUP
+		OW_OUT_LOW();
+#endif
+		OW_DIR_OUT();    // drive bus low
+		_delay_us(2);    // T_INT > 1usec accoding to timing-diagramm
+		if ( b ) {
+			OW_DIR_IN(); // to write "1" release bus, resistor pulls high
+#if OW_USE_INTERNAL_PULLUP
+			OW_OUT_HIGH();
+#endif
+		}
+
+		// "Output data from the DS18B20 is valid for 15usec after the falling
+		// edge that initiated the read time slot. Therefore, the master must 
+		// release the bus and then sample the bus state within 15ussec from 
+		// the start of the slot."
+		_delay_us(15-2-OW_CONF_DELAYOFFSET);
+		
+		if( OW_GET_IN() == 0 ) {
+			b = 0;  // sample at end of read-timeslot
+		}
+	
+		_delay_us(60-15-2+OW_CONF_DELAYOFFSET);
+#if OW_USE_INTERNAL_PULLUP
+		OW_OUT_HIGH();
+#endif
+		OW_DIR_IN();
+	
+		if ( with_parasite_enable ) {
+			ow_parasite_enable();
+		}
+	
+	} /* ATOMIC_BLOCK */
+
+	_delay_us(OW_RECOVERY_TIME); // may be increased for longer wires
+
+	return b;
+}
+
+uint8_t ow_bit_io( uint8_t b )
+{
+	return ow_bit_io_intern( b & 1, 0 );
+}
+
+uint8_t ow_byte_wr( uint8_t b )
+{
+	uint8_t i = 8, j;
+	
+	do {
+		j = ow_bit_io( b & 1 );
+		b >>= 1;
+		if( j ) {
+			b |= 0x80;
+		}
+	} while( --i );
+	
+	return b;
+}
+
+uint8_t ow_byte_wr_with_parasite_enable( uint8_t b )
+{
+	uint8_t i = 8, j;
+	
+	do {
+		if ( i != 1 ) {
+			j = ow_bit_io_intern( b & 1, 0 );
+		} else {
+			j = ow_bit_io_intern( b & 1, 1 );
+		}
+		b >>= 1;
+		if( j ) {
+			b |= 0x80;
+		}
+	} while( --i );
+	
+	return b;
+}
+
+
+uint8_t ow_byte_rd( void )
+{
+	// read by sending only "1"s, so bus gets released
+	// after the init low-pulse in every slot
+	return ow_byte_wr( 0xFF ); 
+}
+
+
+uint8_t ow_rom_search( uint8_t diff, uint8_t *id )
+{
+	uint8_t i, j, next_diff;
+	uint8_t b;
+	
+	if( ow_reset() ) {
+		return OW_PRESENCE_ERR;         // error, no device found <--- early exit!
+	}
+	
+	ow_byte_wr( OW_SEARCH_ROM );        // ROM search command
+	next_diff = OW_LAST_DEVICE;         // unchanged on last device
+	
+	i = OW_ROMCODE_SIZE * 8;            // 8 bytes
+	
+	do {
+		j = 8;                          // 8 bits
+		do {
+			b = ow_bit_io( 1 );         // read bit
+			if( ow_bit_io( 1 ) ) {      // read complement bit
+				if( b ) {               // 0b11
+					return OW_DATA_ERR; // data error <--- early exit!
+				}
+			}
+			else {
+				if( !b ) {              // 0b00 = 2 devices
+					if( diff > i || ((*id & 1) && diff != i) ) {
+						b = 1;          // now 1
+						next_diff = i;  // next pass 0
+					}
+				}
+			}
+			ow_bit_io( b );             // write bit
+			*id >>= 1;
+			if( b ) {
+				*id |= 0x80;            // store bit
+			}
+			
+			i--;
+			
+		} while( --j );
+		
+		id++;                           // next byte
+	
+	} while( i );
+	
+	return next_diff;                   // to continue search
+}
+
+
+static void ow_command_intern( uint8_t command, uint8_t *id, uint8_t with_parasite_enable )
+{
+	uint8_t i;
+
+	ow_reset();
+
+	if( id ) {
+		ow_byte_wr( OW_MATCH_ROM );     // to a single device
+		i = OW_ROMCODE_SIZE;
+		do {
+			ow_byte_wr( *id );
+			id++;
+		} while( --i );
+	} 
+	else {
+		ow_byte_wr( OW_SKIP_ROM );      // to all devices
+	}
+	
+	if ( with_parasite_enable  ) {
+		ow_byte_wr_with_parasite_enable( command );
+	} else {
+		ow_byte_wr( command );
+	}
+}
+
+void ow_command( uint8_t command, uint8_t *id )
+{
+	ow_command_intern( command, id, 0);
+}
+
+void ow_command_with_parasite_enable( uint8_t command, uint8_t *id )
+{
+	ow_command_intern( command, id, 1 );
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onewire.h	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,93 @@
+#ifndef ONEWIRE_H_
+#define ONEWIRE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/*******************************************/
+/* Hardware connection                     */
+/*******************************************/
+
+/* Define OW_ONE_BUS if only one 1-Wire-Bus is used
+   in the application -> shorter code.
+   If not defined make sure to call ow_set_bus() before using 
+   a bus. Runtime bus-select increases code size by around 300 
+   bytes so use OW_ONE_BUS if possible */
+#define OW_ONE_BUS
+
+#ifdef OW_ONE_BUS
+
+#define OW_PIN  PB1
+#define OW_IN   PINB
+#define OW_OUT  PORTB
+#define OW_DDR  DDRB
+#define OW_CONF_DELAYOFFSET 0
+
+#else 
+#if ( F_CPU < 1843200 )
+#warning | Experimental multi-bus-mode is not tested for 
+#warning | frequencies below 1,84MHz. Use OW_ONE_WIRE or
+#warning | faster clock-source (i.e. internal 2MHz R/C-Osc.).
+#endif
+#define OW_CONF_CYCLESPERACCESS 13
+#define OW_CONF_DELAYOFFSET ( (uint16_t)( ((OW_CONF_CYCLESPERACCESS) * 1000000L) / F_CPU ) )
+#endif
+
+// Recovery time (T_Rec) minimum 1usec - increase for long lines 
+// 5 usecs is a value give in some Maxim AppNotes
+// 30u secs seem to be reliable for longer lines
+//#define OW_RECOVERY_TIME        5  /* usec */
+//#define OW_RECOVERY_TIME      300 /* usec */
+#define OW_RECOVERY_TIME         10 /* usec */
+
+// Use AVR's internal pull-up resistor instead of external 4,7k resistor.
+// Based on information from Sascha Schade. Experimental but worked in tests
+// with one DS18B20 and one DS18S20 on a rather short bus (60cm), where both 
+// sensores have been parasite-powered.
+#define OW_USE_INTERNAL_PULLUP     1  /* 0=external, 1=internal */
+
+/*******************************************/
+
+
+#define OW_MATCH_ROM    0x55
+#define OW_SKIP_ROM     0xCC
+#define OW_SEARCH_ROM   0xF0
+
+#define OW_SEARCH_FIRST 0xFF        // start new search
+#define OW_PRESENCE_ERR 0xFF
+#define OW_DATA_ERR     0xFE
+#define OW_LAST_DEVICE  0x00        // last device found
+
+// rom-code size including CRC
+#define OW_ROMCODE_SIZE 8
+
+extern uint8_t ow_reset(void);
+
+extern uint8_t ow_bit_io( uint8_t b );
+extern uint8_t ow_byte_wr( uint8_t b );
+extern uint8_t ow_byte_rd( void );
+
+extern uint8_t ow_rom_search( uint8_t diff, uint8_t *id );
+
+extern void ow_command( uint8_t command, uint8_t *id );
+extern void ow_command_with_parasite_enable( uint8_t command, uint8_t *id );
+
+extern void ow_parasite_enable( void );
+extern void ow_parasite_disable( void );
+extern uint8_t ow_input_pin_state( void );
+
+#ifndef OW_ONE_BUS
+extern void ow_set_bus( volatile uint8_t* in,
+	volatile uint8_t* out,
+	volatile uint8_t* ddr,
+	uint8_t pin );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha1-asm.S	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,883 @@
+/* sha1-asm.S */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2008  Daniel Otte ([email protected])
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ * Author:	Daniel Otte
+ *
+ * License: GPLv3 or later
+*/
+; SHA1 implementation in assembler for AVR
+SHA1_BLOCK_BITS = 512
+SHA1_HASH_BITS = 160
+
+.macro precall
+	/* push r18 - r27, r30 - r31*/
+	push r0
+	push r1
+	push r18
+	push r19
+	push r20
+	push r21
+	push r22
+	push r23
+	push r24
+	push r25
+	push r26
+	push r27
+	push r30
+	push r31
+	clr r1
+.endm
+
+.macro postcall
+	pop r31
+	pop r30
+	pop r27
+	pop r26
+	pop r25
+	pop r24
+	pop r23
+	pop r22
+	pop r21
+	pop r20
+	pop r19
+	pop r18
+	pop r1
+	pop r0
+.endm
+
+
+.macro hexdump length
+	push r27
+	push r26
+	ldi r25, '\r'
+	mov r24, r25
+	call uart_putc
+	ldi r25, '\n'
+	mov r24, r25
+	call uart_putc
+	pop r26
+	pop r27
+	movw r24, r26
+.if \length > 16
+	ldi r22, lo8(16)
+	ldi r23, hi8(16)
+	push r27
+	push r26
+	call uart_hexdump
+	pop r26
+	pop r27
+	adiw r26, 16
+	hexdump \length-16
+.else
+	ldi r22, lo8(\length)
+	ldi r23, hi8(\length)
+	call uart_hexdump
+.endif
+.endm
+
+.macro delay
+/*
+	push r0
+	push r1
+	clr r0
+1:	clr r1
+2:	dec r1
+	brne 2b
+	dec r0
+	brne 1b
+	pop r1
+	pop r0  // */
+.endm
+
+/* X points to Block */
+.macro dbg_hexdump length
+/*
+	precall
+	hexdump \length
+	postcall
+	// */
+.endm
+
+
+
+.section .text
+
+SPL = 0x3D
+SPH = 0x3E
+SREG = 0x3F
+
+
+;
+;sha1_ctx_t is:
+;
+; [h0][h1][h2][h3][h4][length]
+; hn is 32 bit large, length is 64 bit large
+
+;###########################################################
+
+.global sha1_ctx2hash
+; === sha1_ctx2hash ===
+; this function converts a state into a normal hash (bytestring)
+;  param1: the 16-bit destination pointer
+;	given in r25,r24 (r25 is most significant)
+;  param2: the 16-bit pointer to sha1_ctx structure
+;	given in r23,r22
+sha1_ctx2hash:
+	movw r26, r22
+	movw r30, r24
+	ldi r21, 5
+	sbiw r26, 4
+1:
+	ldi r20, 4
+	adiw r26, 8
+2:
+		ld r0, -X
+		st Z+, r0
+	dec r20
+	brne 2b
+
+	dec r21
+	brne 1b
+
+	ret
+
+;###########################################################
+
+.global sha1
+; === sha1 ===
+; this function calculates SHA-1 hashes from messages in RAM
+;  param1: the 16-bit hash destination pointer
+;	given in r25,r24 (r25 is most significant)
+;  param2: the 16-bit pointer to message
+;	given in r23,r22
+;  param3: 32-bit length value (length of message in bits)
+;   given in r21,r20,r19,r18
+sha1:
+sha1_prolog:
+	push r8
+	push r9
+	push r10
+	push r11
+	push r12
+	push r13
+	push r16
+	push r17
+	in r30, SPL
+	in r31, SPH
+	sbiw r30, 5*4+8
+	in r0, SREG
+	cli
+	out SPL, r30
+	out SREG, r0
+	out SPH, r31
+
+	push r25
+	push r24
+	adiw r30, 1
+	movw r16, r30
+
+	movw r8, r18		/* backup of length*/
+	movw r10, r20
+
+	movw r12, r22	/* backup pf msg-ptr */
+
+	movw r24, r16
+	rcall sha1_init
+	/* if length >= 512 */
+1:
+	tst r11
+	brne 2f
+	tst r10
+	breq 4f
+2:
+	movw r24, r16
+	movw r22, r12
+	rcall sha1_nextBlock
+	ldi r19, 64
+	add r12, r19
+	adc r13, r1
+	/* length -= 512 */
+	ldi r19, 0x02
+	sub r9, r19
+	sbc r10, r1
+	sbc r11, r1
+	rjmp 1b
+
+4:
+	movw r24, r16
+	movw r22, r12
+	movw r20, r8
+	rcall sha1_lastBlock
+
+	pop r24
+	pop r25
+	movw r22, r16
+	rcall sha1_ctx2hash
+
+sha1_epilog:
+	in r30, SPL
+	in r31, SPH
+	adiw r30, 5*4+8
+	in r0, SREG
+	cli
+	out SPL, r30
+	out SREG, r0
+	out SPH, r31
+	pop r17
+	pop r16
+	pop r13
+	pop r12
+	pop r11
+	pop r10
+	pop r9
+	pop r8
+	ret
+
+;###########################################################
+
+
+; block MUST NOT be larger than 64 bytes
+
+.global sha1_lastBlock
+; === sha1_lastBlock ===
+; this function does padding & Co. for calculating SHA-1 hashes
+;  param1: the 16-bit pointer to sha1_ctx structure
+;	given in r25,r24 (r25 is most significant)
+;  param2: an 16-bit pointer to 64 byte block to hash
+;	given in r23,r22
+;  param3: an 16-bit integer specifing length of block in bits
+;	given in r21,r20
+sha1_lastBlock_localSpace = (SHA1_BLOCK_BITS/8+1)
+
+
+sha1_lastBlock:
+	cpi r21, 0x02
+	brlo sha1_lastBlock_prolog
+	push r25
+	push r24
+	push r23
+	push r22
+	push r21
+	push r20
+	rcall sha1_nextBlock
+	pop r20
+	pop r21
+	pop r22
+	pop r23
+	pop r24
+	pop r25
+	subi r21, 2
+	ldi r19, 64
+	add r22, r19
+	adc r23, r1
+	rjmp sha1_lastBlock
+sha1_lastBlock_prolog:
+	/* allocate space on stack */
+	in r30, SPL
+	in r31, SPH
+	in r0, SREG
+	subi r30, lo8(64)
+	sbci r31, hi8(64) /* ??? */
+	cli
+	out SPL, r30
+	out SREG, r0
+	out SPH, r31
+
+	adiw r30, 1 /* SP points to next free byte on stack */
+	mov r18, r20 /* r20 = LSB(length) */
+	lsr r18
+	lsr r18
+	lsr r18
+	bst r21, 0	/* may be we should explain this ... */
+	bld r18, 5  /* now: r18 == length/8 (aka. length in bytes) */
+
+
+	movw r26, r22 /* X points to begin of msg */
+	tst r18
+	breq sha1_lastBlock_post_copy
+	mov r1, r18
+sha1_lastBlock_copy_loop:
+	ld r0, X+
+	st Z+, r0
+	dec r1
+	brne sha1_lastBlock_copy_loop
+sha1_lastBlock_post_copy:
+sha1_lastBlock_insert_stuffing_bit:
+	ldi r19, 0x80
+	mov r0,r19
+	ldi r19, 0x07
+	and r19, r20 /* if we are in bitmode */
+	breq 2f	/* no bitmode */
+1:
+	lsr r0
+	dec r19
+	brne 1b
+	ld r19, X
+/* maybe we should do some ANDing here, just for safety */
+	or r0, r19
+2:
+	st Z+, r0
+	inc r18
+
+/* checking stuff here */
+	cpi r18, 64-8+1
+	brsh 0f
+	rjmp sha1_lastBlock_insert_zeros
+0:
+	/* oh shit, we landed here */
+	/* first we have to fill it up with zeros */
+	ldi r19, 64
+	sub r19, r18
+	breq 2f
+1:
+	st Z+, r1
+	dec r19
+	brne 1b
+2:
+	sbiw r30, 63
+	sbiw r30,  1
+	movw r22, r30
+
+	push r31
+	push r30
+	push r25
+	push r24
+	push r21
+	push r20
+	rcall sha1_nextBlock
+	pop r20
+	pop r21
+	pop r24
+	pop r25
+	pop r30
+	pop r31
+
+	/* now we should subtract 512 from length */
+	movw r26, r24
+	adiw r26, 4*5+1 /* we can skip the lowest byte */
+	ld r19, X
+	subi r19, hi8(512)
+	st X+, r19
+	ldi r18, 6
+1:
+	ld r19, X
+	sbci r19, 0
+	st X+, r19
+	dec r18
+	brne 1b
+
+;	clr r18 /* not neccessary ;-) */
+	/* reset Z pointer to begin of block */
+
+sha1_lastBlock_insert_zeros:
+	ldi r19, 64-8
+	sub r19, r18
+	breq sha1_lastBlock_insert_length
+	clr r1
+1:
+	st Z+, r1	/* r1 is still zero */
+	dec r19
+	brne 1b
+
+;	rjmp sha1_lastBlock_epilog
+sha1_lastBlock_insert_length:
+	movw r26, r24	/* X points to state */
+	adiw r26, 5*4	/* X points to (state.length) */
+	adiw r30, 8		/* Z points one after the last byte of block */
+	ld r0, X+
+	add r0, r20
+	st -Z, r0
+	ld r0, X+
+	adc r0, r21
+	st -Z, r0
+	ldi r19, 6
+1:
+	ld r0, X+
+	adc r0, r1
+	st -Z, r0
+	dec r19
+	brne 1b
+
+	sbiw r30, 64-8
+	movw r22, r30
+	rcall sha1_nextBlock
+
+sha1_lastBlock_epilog:
+	in r30, SPL
+	in r31, SPH
+	in r0, SREG
+	adiw r30, 63 ; lo8(64)
+	adiw r30,  1  ; hi8(64)
+	cli
+	out SPL, r30
+	out SREG, r0
+	out SPH, r31
+	clr r1
+	ret
+
+/**/
+;###########################################################
+
+.global sha1_nextBlock
+; === sha1_nextBlock ===
+; this is the core function for calculating SHA-1 hashes
+;  param1: the 16-bit pointer to sha1_ctx structure
+;	given in r25,r24 (r25 is most significant)
+;  param2: an 16-bit pointer to 64 byte block to hash
+;	given in r23,r22
+sha1_nextBlock_localSpace = (16+5+1)*4 ; 16 32-bit values for w array and 5 32-bit values for a array (total 84 byte)
+
+xtmp = 0
+xNULL = 1
+W1 = 10
+W2 = 11
+T1	= 12
+T2	= 13
+T3	= 14
+T4	= 15
+LoopC = 16
+S	  = 17
+tmp1 = 18
+tmp2 = 19
+tmp3 = 20
+tmp4 = 21
+F1 = 22
+F2 = 23
+F3 = 24
+F4 = 25
+
+/* byteorder: high number <--> high significance */
+sha1_nextBlock:
+ ; initial, let's make some space ready for local vars
+ 			 /* replace push & pop by mem ops? */
+	push r10
+	push r11
+	push r12
+	push r13
+	push r14
+	push r15
+	push r16
+	push r17
+	push r28
+	push r29
+	in r20, SPL
+	in r21, SPH
+	movw r18, r20			;backup SP
+;	movw r26, r20			; X points to free space on stack /* maybe removeable? */
+	movw r30, r22			; Z points to message
+	subi r20, lo8(sha1_nextBlock_localSpace) ;sbiw can do only up to 63
+	sbci r21, hi8(sha1_nextBlock_localSpace)
+	movw r26, r20			; X points to free space on stack
+	in r0, SREG
+	cli ; we want to be uninterrupted while updating SP
+	out SPL, r20
+	out SREG, r0
+	out SPH, r21
+
+	push r18
+	push r19 /* push old SP on new stack */
+	push r24
+	push r25 /* param1 will be needed later */
+
+	/* load a[] with state */
+	movw 28, r24 /* load pointer to state in Y */
+	adiw r26, 1 ; X++
+
+	ldi LoopC, 5*4
+1:	ld tmp1, Y+
+	st X+, tmp1
+	dec LoopC
+	brne 1b
+
+	movw W1, r26 /* save pointer to w[0] */
+	/* load w[] with endian fixed message */
+		/* we might also use the changeendian32() function at bottom */
+	movw r30, r22 /* mv param2 (ponter to msg) to Z */
+	ldi LoopC, 16
+1:
+	ldd tmp1, Z+3
+	st X+, tmp1
+	ldd tmp1, Z+2
+	st X+, tmp1
+	ldd tmp1, Z+1
+	st X+, tmp1
+	ld tmp1, Z
+	st X+, tmp1
+	adiw r30, 4
+	dec LoopC
+	brne 1b
+
+	;clr LoopC /* LoopC is named t in FIPS 180-2 */
+	clr xtmp
+sha1_nextBlock_mainloop:
+	mov S, LoopC
+	lsl S
+	lsl S
+	andi S, 0x3C /* S is a bytepointer so *4 */
+	/* load w[s] */
+	movw r26, W1
+	add r26, S /* X points at w[s] */
+	adc r27, xNULL
+	ld T1, X+
+	ld T2, X+
+	ld T3, X+
+	ld T4, X+
+
+/*
+	push r26
+	push r27
+	push T4
+	push T3
+	push T2
+	push T1
+	in r26, SPL
+	in r27, SPH
+	adiw r26, 1
+	dbg_hexdump 4
+	pop T1
+	pop T2
+	pop T3
+	pop T4
+	pop r27
+	pop r26
+*/
+
+	cpi LoopC, 16
+	brlt sha1_nextBlock_mainloop_core
+	/* update w[s] */
+	ldi tmp1, 2*4
+	rcall 1f
+	ldi tmp1, 8*4
+	rcall 1f
+	ldi tmp1, 13*4
+	rcall 1f
+	rjmp 2f
+1:		/* this might be "outsourced" to save the jump above */
+	add tmp1, S
+	andi tmp1, 0x3f
+	movw r26, W1
+	add r26, tmp1
+	adc r27, xNULL
+	ld tmp2, X+
+	eor T1, tmp2
+	ld tmp2, X+
+	eor T2, tmp2
+	ld tmp2, X+
+	eor T3, tmp2
+	ld tmp2, X+
+	eor T4, tmp2
+	ret
+2:	/* now we just hav to do a ROTL(T) and save T back */
+	mov tmp2, T4
+	rol tmp2
+	rol T1
+	rol T2
+	rol T3
+	rol T4
+	movw r26, W1
+	add r26, S
+	adc r27, xNULL
+	st X+, T1
+	st X+, T2
+	st X+, T3
+	st X+, T4
+
+sha1_nextBlock_mainloop_core:	/* ther core function; T=ROTL5(a) ....*/
+								/* T already contains w[s] */
+	movw r26, W1
+	sbiw r26, 4*1		/* X points at a[4] aka e */
+	ld tmp1, X+
+	add T1, tmp1
+	ld tmp1, X+
+	adc T2, tmp1
+	ld tmp1, X+
+	adc T3, tmp1
+	ld tmp1, X+
+	adc T4, tmp1		/* T = w[s]+e */
+	sbiw r26, 4*5		/* X points at a[0] aka a */
+	ld F1, X+
+	ld F2, X+
+	ld F3, X+
+	ld F4, X+
+	mov tmp1, F4		/* X points at a[1] aka b */
+	ldi tmp2, 5
+1:
+	rol tmp1
+	rol F1
+	rol F2
+	rol F3
+	rol F4
+	dec tmp2
+	brne 1b
+
+	add T1, F1
+	adc T2, F2
+	adc T3, F3
+	adc T4, F4 /* T = ROTL(a,5) + e + w[s] */
+
+	/* now we have to do this fucking conditional stuff */
+	ldi r30, lo8(sha1_nextBlock_xTable)
+	ldi r31, hi8(sha1_nextBlock_xTable)
+	add r30, xtmp
+	adc r31, xNULL
+	lpm tmp1, Z
+	cp tmp1, LoopC
+	brne 1f
+	inc xtmp
+1:	ldi r30, lo8(sha1_nextBlock_KTable)
+	ldi r31, hi8(sha1_nextBlock_KTable)
+	lsl xtmp
+	lsl xtmp
+	add r30, xtmp
+	adc r31, xNULL
+	lsr xtmp
+	lsr xtmp
+
+	lpm tmp1, Z+
+	add T1, tmp1
+	lpm tmp1, Z+
+	adc T2, tmp1
+	lpm tmp1, Z+
+	adc T3, tmp1
+	lpm tmp1, Z+
+	adc T4, tmp1
+			/* T = ROTL(a,5) + e + kt + w[s] */
+
+	/* Z-4 is just pointing to kt ... */
+	movw r28, r26 /* copy X in Y */
+	adiw r30, 3*4 /* now Z points to the rigth locatin in our jump-vector-table */
+	lsr r31
+	ror r30
+
+	icall
+	mov F1, tmp1
+	icall
+	mov F2, tmp1
+	icall
+	mov F3, tmp1
+	icall
+
+	add T1, F1
+	adc T2, F2
+	adc T3, F3
+	adc T4, tmp1 /* T = ROTL5(a) + f_t(b,c,d) + e + k_t + w[s] */
+				 /* X points still at a[1] aka b, Y points at a[2] aka c */
+	/* update a[] */
+sha1_nextBlock_update_a:
+	/*first we move all vars in a[] "one up" e=d, d=c, c=b, b=a*/
+	//adiw r28, 3*4  /* Y should point at a[4] aka e */
+	movw r28, W1
+	sbiw r28, 4
+
+	ldi tmp2, 4*4
+1:
+	ld tmp1, -Y
+	std Y+4, tmp1
+	dec tmp2
+	brne 1b
+	/* Y points at a[0] aka a*/
+
+	movw r28, W1
+	sbiw r28, 5*4
+	/* store T in a[0] aka a */
+	st Y+, T1
+	st Y+, T2
+	st Y+, T3
+	st Y+, T4
+	/* Y points at a[1] aka b*/
+
+	/* rotate c */
+	ldd T1, Y+1*4
+	ldd T2, Y+1*4+1
+	ldd T3, Y+1*4+2
+	ldd T4, Y+1*4+3
+	mov tmp1, T1
+	ldi tmp2, 2
+1:	ror tmp1
+	ror T4
+	ror T3
+	ror T2
+	ror T1
+	dec tmp2
+	brne 1b
+	std Y+1*4+0, T1
+	std Y+1*4+1, T2
+	std Y+1*4+2, T3
+	std Y+1*4+3, T4
+/*
+	push r27
+	push r26
+	movw r26, W1
+	sbiw r26, 4*5
+	dbg_hexdump 4*5
+	pop r26
+	pop r27
+*/
+	inc LoopC
+	cpi LoopC, 80
+	brge 1f
+	rjmp sha1_nextBlock_mainloop
+/**************************************/
+1:
+   /* littel patch */
+	sbiw r28, 4
+
+/* add a[] to state and inc length */
+	pop r27
+	pop r26		/* now X points to state (and Y still at a[0]) */
+	ldi tmp4, 5
+1:	clc
+	ldi tmp3, 4
+2:	ld tmp1, X
+	ld tmp2, Y+
+	adc tmp1, tmp2
+	st X+, tmp1
+	dec tmp3
+	brne 2b
+	dec tmp4
+	brne 1b
+
+	/* now length += 512 */
+	adiw r26, 1 /* we skip the least significant byte */
+	ld tmp1, X
+	ldi tmp2, hi8(512) /* 2 */
+	add tmp1, tmp2
+	st X+, tmp1
+	ldi tmp2, 6
+1:
+	ld tmp1, X
+	adc tmp1, xNULL
+	st X+, tmp1
+	dec tmp2
+	brne 1b
+
+; EPILOG
+sha1_nextBlock_epilog:
+/* now we should clean up the stack */
+	pop r21
+	pop r20
+	in r0, SREG
+	cli ; we want to be uninterrupted while updating SP
+	out SPL, r20
+	out SREG, r0
+	out SPH, r21
+
+	clr r1
+	pop r29
+	pop r28
+	pop r17
+	pop r16
+	pop r15
+	pop r14
+	pop r13
+	pop r12
+	pop r11
+	pop r10
+	ret
+
+sha1_nextBlock_xTable:
+.byte 20,40,60,0
+sha1_nextBlock_KTable:
+.int	0x5a827999
+.int	0x6ed9eba1
+.int	0x8f1bbcdc
+.int	0xca62c1d6
+sha1_nextBlock_JumpTable:
+rjmp sha1_nextBlock_Ch
+	nop
+rjmp sha1_nextBlock_Parity
+	nop
+rjmp sha1_nextBlock_Maj
+	nop
+rjmp sha1_nextBlock_Parity
+
+	 /* X and Y still point at a[1] aka b ; return value in tmp1 */
+sha1_nextBlock_Ch:
+	ld tmp1, Y+
+	mov tmp2, tmp1
+	com tmp2
+	ldd tmp3, Y+3	/* load from c */
+	and tmp1, tmp3
+	ldd tmp3, Y+7	/* load from d */
+	and tmp2, tmp3
+	eor tmp1, tmp2
+	ret
+
+sha1_nextBlock_Maj:
+	ld tmp1, Y+
+	mov tmp2, tmp1
+	ldd tmp3, Y+3	/* load from c */
+	and tmp1, tmp3
+	ldd tmp4, Y+7	/* load from d */
+	and tmp2, tmp4
+	eor tmp1, tmp2
+	and tmp3, tmp4
+	eor tmp1, tmp3
+	ret
+
+sha1_nextBlock_Parity:
+	ld tmp1, Y+
+	ldd tmp2, Y+3	/* load from c */
+	eor tmp1, tmp2
+	ldd tmp2, Y+7	/* load from d */
+	eor tmp1, tmp2
+	ret
+/*
+ch_str:			.asciz "\r\nCh"
+maj_str:		.asciz "\r\nMaj"
+parity_str:	.asciz "\r\nParity"
+*/
+;###########################################################
+
+.global sha1_init
+;void sha1_init(sha1_ctx_t *state){
+;	DEBUG_S("\r\nSHA1_INIT");
+;	state->h[0] = 0x67452301;
+;	state->h[1] = 0xefcdab89;
+;	state->h[2] = 0x98badcfe;
+;	state->h[3] = 0x10325476;
+;	state->h[4] = 0xc3d2e1f0;
+;	state->length = 0;
+;}
+; param1: (Func3,r24) 16-bit pointer to sha1_ctx_t struct in ram
+; modifys: Z(r30,r31), Func1, r22
+sha1_init:
+	movw r26, r24 ; (24,25) --> (26,27) load X with param1
+	ldi r30, lo8((sha1_init_vector))
+	ldi r31, hi8((sha1_init_vector))
+	ldi r22, 5*4 /* bytes to copy */
+sha1_init_vloop:
+	lpm r23, Z+
+	st X+, r23
+	dec r22
+	brne sha1_init_vloop
+	ldi r22, 8
+sha1_init_lloop:
+	st X+, r1
+	dec r22
+	brne sha1_init_lloop
+	ret
+
+sha1_init_vector:
+.int 0x67452301;
+.int 0xefcdab89;
+.int 0x98badcfe;
+.int 0x10325476;
+.int 0xc3d2e1f0;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha1.c	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,243 @@
+/* sha1.c */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2008, 2009  Daniel Otte ([email protected])
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * \file	sha1.c
+ * \author	Daniel Otte
+ * \date	2006-10-08
+ * \license GPLv3 or later
+ * \brief SHA-1 implementation.
+ *
+ */
+
+#include <string.h> /* memcpy & co */
+#include <stdint.h>
+#include "config.h"
+#include "debug.h"
+#include "sha1.h"
+
+#ifdef DEBUG
+#  undef DEBUG
+#endif
+
+#include "cli.h"
+
+#define LITTLE_ENDIAN
+
+/********************************************************************************************************/
+
+/**
+ * \brief initialises given SHA-1 context
+ *
+ */
+void sha1_init(sha1_ctx_t *state){
+	DEBUG_S("\r\nSHA1_INIT");
+	state->h[0] = 0x67452301;
+	state->h[1] = 0xefcdab89;
+	state->h[2] = 0x98badcfe;
+	state->h[3] = 0x10325476;
+	state->h[4] = 0xc3d2e1f0;
+	state->length = 0;
+}
+
+/********************************************************************************************************/
+/* some helping functions */
+uint32_t rotl32(uint32_t n, uint8_t bits){
+	return ((n<<bits) | (n>>(32-bits)));
+}
+
+uint32_t change_endian32(uint32_t x){
+	return (((x)<<24) | ((x)>>24) | (((x)& 0x0000ff00)<<8) | (((x)& 0x00ff0000)>>8));
+}
+
+
+/* three SHA-1 inner functions */
+uint32_t ch(uint32_t x, uint32_t y, uint32_t z){
+	DEBUG_S("\r\nCH");
+	return ((x&y)^((~x)&z));
+}
+
+uint32_t maj(uint32_t x, uint32_t y, uint32_t z){
+	DEBUG_S("\r\nMAJ");
+	return ((x&y)^(x&z)^(y&z));
+}
+
+uint32_t parity(uint32_t x, uint32_t y, uint32_t z){
+	DEBUG_S("\r\nPARITY");
+	return ((x^y)^z);
+}
+
+/********************************************************************************************************/
+/**
+ * \brief "add" a block to the hash
+ * This is the core function of the hash algorithm. To understand how it's working
+ * and what thoese variables do, take a look at FIPS-182. This is an "alternativ" implementation
+ */
+
+#define MASK 0x0000000f
+
+typedef uint32_t (*pf_t)(uint32_t x, uint32_t y, uint32_t z);
+
+void sha1_nextBlock (sha1_ctx_t *state, const void* block){
+	uint32_t a[5];
+	uint32_t w[16];
+	uint32_t temp;
+	uint8_t t,s,fi, fib;
+	pf_t f[] = {ch,parity,maj,parity};
+	uint32_t k[4]={	0x5a827999,
+					0x6ed9eba1,
+					0x8f1bbcdc,
+					0xca62c1d6};
+
+	/* load the w array (changing the endian and so) */
+	for(t=0; t<16; ++t){
+		w[t] = change_endian32(((uint32_t*)block)[t]);
+	}
+
+#if DEBUG
+	uint8_t dbgi;
+	for(dbgi=0; dbgi<16; ++dbgi){
+		/*
+		DEBUG_S("\n\rBlock:");
+		DEBUG_B(dbgi);
+		DEBUG_C(':');
+		*/
+		cli_putstr_P(PSTR("\r\nBlock:"));
+		cli_hexdump(&dbgi, 1);
+		cli_putc(':');
+		cli_hexdump(&(w[dbgi]) ,4);
+	}
+#endif
+
+	/* load the state */
+	memcpy(a, state->h, 5*sizeof(uint32_t));
+
+
+	/* the fun stuff */
+	for(fi=0,fib=0,t=0; t<=79; ++t){
+		s = t & MASK;
+		if(t>=16){
+			#if DEBUG
+			 DEBUG_S("\r\n ws = "); cli_hexdump(&(w[s]), 4);
+			#endif
+			w[s] = rotl32( w[(s+13)&MASK] ^ w[(s+8)&MASK] ^
+				 w[(s+ 2)&MASK] ^ w[s] ,1);
+			#ifdef DEBUG
+			 DEBUG_S(" --> ws = "); cli_hexdump(&(w[s]), 4);
+			#endif
+		}
+
+		uint32_t dtemp;
+		temp = rotl32(a[0],5) + (dtemp=f[fi](a[1],a[2],a[3])) + a[4] + k[fi] + w[s];
+		memmove(&(a[1]), &(a[0]), 4*sizeof(uint32_t)); /* e=d; d=c; c=b; b=a; */
+		a[0] = temp;
+		a[2] = rotl32(a[2],30); /* we might also do rotr32(c,2) */
+		fib++;
+		if(fib==20){
+			fib=0;
+			fi = (fi+1)%4;
+		}
+		#if DEBUG
+		/* debug dump */
+		DEBUG_S("\r\nt = "); DEBUG_B(t);
+		DEBUG_S("; a[]: ");
+		 cli_hexdump(a, 5*4);
+		DEBUG_S("; k = ");
+		 cli_hexdump(&(k[t/20]), 4);
+		DEBUG_S("; f(b,c,d) = ");
+		 cli_hexdump(&dtemp, 4);
+		#endif
+	}
+
+	/* update the state */
+	for(t=0; t<5; ++t){
+		state->h[t] += a[t];
+	}
+	state->length += 512;
+}
+
+/********************************************************************************************************/
+
+void sha1_lastBlock(sha1_ctx_t *state, const void* block, uint16_t length){
+	uint8_t lb[SHA1_BLOCK_BYTES]; /* local block */
+	while(length>=SHA1_BLOCK_BITS){
+		sha1_nextBlock(state, block);
+		length -= SHA1_BLOCK_BITS;
+		block = (uint8_t*)block + SHA1_BLOCK_BYTES;
+	}
+	state->length += length;
+	memset(lb, 0, SHA1_BLOCK_BYTES);
+	memcpy (lb, block, (length+7)>>3);
+
+	/* set the final one bit */
+	lb[length>>3] |= 0x80>>(length & 0x07);
+
+	if (length>512-64-1){ /* not enouth space for 64bit length value */
+		sha1_nextBlock(state, lb);
+		state->length -= 512;
+		memset(lb, 0, SHA1_BLOCK_BYTES);
+	}
+	/* store the 64bit length value */
+#if defined LITTLE_ENDIAN
+	 	/* this is now rolled up */
+	uint8_t i;
+	for (i=0; i<8; ++i){
+		lb[56+i] = ((uint8_t*)&(state->length))[7-i];
+	}
+#elif defined BIG_ENDIAN
+	*((uint64_t)&(lb[56])) = state->length;
+#endif
+	sha1_nextBlock(state, lb);
+}
+
+/********************************************************************************************************/
+
+void sha1_ctx2hash (void *dest, sha1_ctx_t *state){
+#if defined LITTLE_ENDIAN
+	uint8_t i;
+	for(i=0; i<5; ++i){
+		((uint32_t*)dest)[i] = change_endian32(state->h[i]);
+	}
+#elif BIG_ENDIAN
+	if (dest != state->h)
+		memcpy(dest, state->h, SHA1_HASH_BITS/8);
+#else
+# error unsupported endian type!
+#endif
+}
+
+/********************************************************************************************************/
+/**
+ *
+ *
+ */
+void sha1 (void *dest, const void* msg, uint32_t length){
+	sha1_ctx_t s;
+	DEBUG_S("\r\nBLA BLUB");
+	sha1_init(&s);
+	while(length & (~0x0001ff)){ /* length>=512 */
+		DEBUG_S("\r\none block");
+		sha1_nextBlock(&s, msg);
+		msg = (uint8_t*)msg + SHA1_BLOCK_BITS/8; /* increment pointer to next block */
+		length -= SHA1_BLOCK_BITS;
+	}
+	sha1_lastBlock(&s, msg, length);
+	sha1_ctx2hash(dest, &s);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha1.h	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,119 @@
+/* sha1.h */
+/*
+    This file is part of the AVR-Crypto-Lib.
+    Copyright (C) 2008  Daniel Otte ([email protected])
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * \file	sha1.h
+ * \author	Daniel Otte
+ * \email   [email protected]
+ * \date	2006-10-08
+ * \license GPLv3 or later
+ * \brief   SHA-1 declaration.
+ * \ingroup SHA-1
+ * 
+ */
+ 
+#ifndef SHA1_H_
+#define SHA1_H_
+
+#include <stdint.h>
+/** \def SHA1_HASH_BITS
+ * definees the size of a SHA-1 hash in bits 
+ */
+
+/** \def SHA1_HASH_BYTES
+ * definees the size of a SHA-1 hash in bytes 
+ */
+
+/** \def SHA1_BLOCK_BITS
+ * definees the size of a SHA-1 input block in bits 
+ */
+
+/** \def SHA1_BLOCK_BYTES
+ * definees the size of a SHA-1 input block in bytes 
+ */
+#define SHA1_HASH_BITS  160
+#define SHA1_HASH_BYTES (SHA1_HASH_BITS/8)
+#define SHA1_BLOCK_BITS 512
+#define SHA1_BLOCK_BYTES (SHA1_BLOCK_BITS/8)
+
+/** \typedef sha1_ctx_t
+ * \brief SHA-1 context type
+ * 
+ * A vatiable of this type may hold the state of a SHA-1 hashing process
+ */
+typedef struct {
+	uint32_t h[5];
+	uint64_t length;
+} sha1_ctx_t;
+
+/** \typedef sha1_hash_t
+ * \brief hash value type
+ * A variable of this type may hold a SHA-1 hash value 
+ */
+/*
+typedef uint8_t sha1_hash_t[SHA1_HASH_BITS/8];
+*/
+
+/** \fn sha1_init(sha1_ctx_t *state)
+ * \brief initializes a SHA-1 context
+ * This function sets a ::sha1_ctx_t variable to the initialization vector
+ * for SHA-1 hashing.
+ * \param state pointer to the SHA-1 context variable
+ */
+void sha1_init(sha1_ctx_t *state);
+
+/** \fn sha1_nextBlock(sha1_ctx_t *state, const void* block)
+ *  \brief process one input block
+ * This function processes one input block and updates the hash context 
+ * accordingly
+ * \param state pointer to the state variable to update
+ * \param block pointer to the message block to process
+ */
+void sha1_nextBlock (sha1_ctx_t *state, const void* block);
+
+/** \fn sha1_lastBlock(sha1_ctx_t *state, const void* block, uint16_t length_b)
+ * \brief processes the given block and finalizes the context
+ * This function processes the last block in a SHA-1 hashing process.
+ * The block should have a maximum length of a single input block.
+ * \param state pointer to the state variable to update and finalize
+ * \param block pointer to themessage block to process
+ * \param length_b length of the message block in bits  
+ */
+void sha1_lastBlock (sha1_ctx_t *state, const void* block, uint16_t length_b);
+
+/** \fn sha1_ctx2hash(sha1_hash_t *dest, sha1_ctx_t *state)
+ * \brief convert a state variable into an actual hash value
+ * Writes the hash value corresponding to the state to the memory pointed by dest.
+ * \param dest pointer to the hash value destination
+ * \param state pointer to the hash context
+ */ 
+void sha1_ctx2hash (void *dest, sha1_ctx_t *state);
+
+/** \fn sha1(sha1_hash_t *dest, const void* msg, uint32_t length_b)
+ * \brief hashing a message which in located entirely in RAM
+ * This function automatically hashes a message which is entirely in RAM with
+ * the SHA-1 hashing algorithm.
+ * \param dest pointer to the hash value destination
+ * \param msg  pointer to the message which should be hashed
+ * \param length_b length of the message in bits
+ */ 
+void sha1(void *dest, const void* msg, uint32_t length_b);
+
+
+
+#endif /*SHA1_H_*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simple_ds18b20.c	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,192 @@
+// Matt Johnston 2012
+// Based on ds18x20.c by Martin Thomas, in turn based on code by 
+// Peter // Dannegger and others.
+//
+#include <stdio.h>
+#include <avr/pgmspace.h>
+
+#include "ds18x20.h"
+#include "onewire.h"
+#include "crc8.h"
+
+#include "simple_ds18b20.h"
+
+uint8_t 
+simple_ds18b20_start_meas(uint8_t id[])
+{
+	uint8_t ret;
+
+	ow_reset();
+	if( ow_input_pin_state() ) { // only send if bus is "idle" = high
+		ow_command_with_parasite_enable(DS18X20_CONVERT_T, id);
+		ret = DS18X20_OK;
+	} 
+	else { 
+		ret = DS18X20_START_FAIL;
+	}
+
+	return ret;
+}
+
+static uint8_t 
+read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n )
+{
+	uint8_t i;
+	uint8_t ret;
+
+	ow_command( DS18X20_READ, id );
+	for ( i = 0; i < n; i++ ) {
+		sp[i] = ow_byte_rd();
+	}
+	if ( crc8( &sp[0], DS18X20_SP_SIZE ) ) {
+		ret = DS18X20_ERROR_CRC;
+	} else {
+		ret = DS18X20_OK;
+	}
+
+	return ret;
+}
+
+int16_t 
+ds18b20_raw16_to_decicelsius(uint16_t measure)
+{
+	uint8_t  negative;
+	int16_t  decicelsius;
+	uint16_t fract;
+
+	// check for negative 
+	if ( measure & 0x8000 )  {
+		negative = 1;       // mark negative
+		measure ^= 0xffff;  // convert to positive => (twos complement)++
+		measure++;
+	}
+	else {
+		negative = 0;
+	}
+
+	decicelsius = (measure >> 4);
+	decicelsius *= 10;
+
+	// decicelsius += ((measure & 0x000F) * 640 + 512) / 1024;
+	// 625/1000 = 640/1024
+	fract = ( measure & 0x000F ) * 640;
+	if ( !negative ) {
+		fract += 512;
+	}
+	fract /= 1024;
+	decicelsius += fract;
+
+	if ( negative ) {
+		decicelsius = -decicelsius;
+	}
+
+	if ( decicelsius == 850 || decicelsius < -550 || decicelsius > 1250 ) {
+		return DS18X20_INVALID_DECICELSIUS;
+	} else {
+		return decicelsius;
+	}
+}
+
+uint8_t 
+simple_ds18b20_read_decicelsius( uint8_t id[], int16_t *decicelsius )
+{
+    uint16_t reading;
+	uint8_t ret;
+
+    ret = simple_ds18b20_read_raw(id, &reading);
+    if (ret == DS18X20_OK)
+    {
+        *decicelsius = ds18b20_raw16_to_decicelsius(reading);
+    }
+    return ret;
+}
+
+uint8_t 
+simple_ds18b20_read_raw( uint8_t id[], uint16_t *reading )
+{
+	uint8_t sp[DS18X20_SP_SIZE];
+	uint8_t ret;
+	
+	if (id)
+	{
+		ow_reset();
+	}
+	ret = read_scratchpad( id, sp, DS18X20_SP_SIZE );
+	if ( ret == DS18X20_OK ) {
+        *reading = sp[0] | (sp[1] << 8);
+	}
+	return ret;
+}
+
+static void 
+printhex_nibble(const unsigned char b, FILE *stream)
+{
+	unsigned char  c = b & 0x0f;
+	if ( c > 9 ) { 
+		c += 'A'-10; 
+	}
+	else {
+		c += '0';
+	}
+	fputc(c, stream);
+}
+
+void 
+printhex_byte(const unsigned char b, FILE *stream)
+{
+	printhex_nibble( b >> 4, stream);
+	printhex_nibble( b, stream);
+}
+
+void
+printhex(uint8_t *id, uint8_t n, FILE *stream)
+{
+	for (uint8_t i = 0; i < n; i++)
+	{
+		if (i > 0)
+		{
+			fputc(' ', stream);
+		}
+		printhex_byte(id[i], stream);
+	}
+}
+
+
+uint8_t 
+simple_ds18b20_read_all()
+{
+	uint8_t id[OW_ROMCODE_SIZE];
+	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 OW_PRESENCE_ERR; // <--- early exit!
+		}
+		
+		if( diff == OW_DATA_ERR ) {
+			printf_P( PSTR("Bus Error\r") );
+			return OW_DATA_ERR;     // <--- early exit!
+		}
+
+		int16_t decicelsius;
+		uint8_t ret = simple_ds18b20_read_decicelsius(NULL, &decicelsius);
+		if (ret != DS18X20_OK)
+		{
+			printf_P(PSTR("Failed reading\r"));
+			return OW_DATA_ERR;
+		}
+
+		printf_P(PSTR("DS18B20 %d: "), diff);
+		if (crc8(id, OW_ROMCODE_SIZE))
+		{
+			printf_P(PSTR("CRC fail"));
+		}
+		printhex(id, OW_ROMCODE_SIZE, stdout);
+		printf_P(PSTR(" %d.%d ºC\n"), decicelsius/10, decicelsius % 10);
+	}
+	printf_P(PSTR("Done sensors\n"));
+	return DS18X20_OK;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simple_ds18b20.h	Sat Jun 01 01:38:42 2013 +0800
@@ -0,0 +1,16 @@
+#ifndef SIMPLE_DS18B20_H_
+#define SIMPLE_DS18B20_H_
+#include <stdint.h>
+#include <stdio.h>
+
+#include "ds18x20.h"
+
+uint8_t simple_ds18b20_start_meas(uint8_t id[]);
+void printhex(uint8_t *id, uint8_t n, FILE *stream);
+void printhex_byte( const unsigned char  b, FILE *stream );
+uint8_t simple_ds18b20_read_decicelsius( uint8_t id[], int16_t *decicelsius );
+int16_t ds18b20_raw16_to_decicelsius(uint16_t measure);
+uint8_t simple_ds18b20_read_raw( uint8_t id[], uint16_t *reading );
+uint8_t simple_ds18b20_read_all();
+
+#endif // SIMPLE_DS18B20_H_