 #endif
 }
 
+/* End of timer interrupt code */
+
 // the loop routine runs over and over again forever:
 void setup() {
   pinMode(out, OUTPUT);

  pinMode(in, INPUT);
  digitalWrite(out, HIGH);
  digitalWrite(debug, HIGH);
  Serial.begin(9600);
  Serial.print("Start. timerPreload=");
  Serial.println(timerPreload);
  setupTimer();
}

void sendSequence(const unsigned char* seq)
{
  Serial.println("Sending sequence");
  static unsigned long time = micros();
  for (int c = 0; seq[c] != 3; ++c) {
    if (seq[c] == 2) {
      digitalWrite(out, HIGH);
      digitalWrite(debug, HIGH);
      delayMicroseconds(52 * 12);
      time = micros();
    } else {
      digitalWrite(out, seq[c]);
      digitalWrite(debug, seq[c]);
      time += 52;
      unsigned int delta = time - micros();
      delayMicroseconds(delta);
    }
  }
  digitalWrite(out, HIGH);
  digitalWrite(debug, HIGH);
  Serial.println("Done sending sequence");
}

// sends stuff from sequence, sequenceAtBit/sequenceAtByte
void sendBinarySequenceHw()
{
  noInterrupts();
  writeBitsLeft = sequenceAt * 8 + sequenceAtBit;
  writeCurBit = 0;
  writeCurByte = 0;
  interrupts();
  
  while (writeBitsLeft > 0) {
    // wait for writing to go through
  }
  Serial.println(".");
}

void doit() {
  sendSequence(initsequence);
}

void baseLoop() {
  if (Serial.available()) {
    char ch = Serial.read();
    switch (ch) {
      case 'i': {
        doit();
      } break;
      case '0': {
        if (sequenceAt < sequenceSize) {
          sequence[sequenceAt++] = 0;
        } else {
          Serial.println("Sequence is too long");
        }
      } break;
      case '1': {
        if (sequenceAt < sequenceSize) {
          sequence[sequenceAt++] = 1;
        } else {
          Serial.println("Sequence is too long");
        }
      } break;
      case 'b': {
        sequenceAt = 0;
        sequenceAtBit = 0;
        inBinarySequence = true;
      } break;
      case ';': {
        if (!prevSequenceSize || sequenceAt > 0) {
          sequence[sequenceAt++] = 3;
        } else {
          sequenceAt = prevSequenceSize;
        }
        Serial.println(sequenceAt);
        for (int c = 0; c < sequenceAt; ++c) {
          Serial.print((int) sequence[c]);
        }
        Serial.println();
        sendSequence(sequence);
        prevSequenceSize = sequenceAt;
        sequenceAt = 0;
      } break;
    }
  }
}

void advanceBit() {
  if (++sequenceAtBit == 8) {
    ++sequenceAt;
    sequenceAtBit = 0;
  }
  if (sequenceAt == sequenceSize) {
    inBinarySequence = false;
  }
}

void binarySequenceLoop() {
  if (Serial.available()) {
    char ch = Serial.read();
    switch (ch) {
      case '1': {
        sequence[sequenceAt] |= (1 << sequenceAtBit);
        advanceBit();
      } break;
      case '0': {
        sequence[sequenceAt] &= ~(1 << sequenceAtBit);
        advanceBit();
      } break;
      case ';': {
#if 0
        Serial.print("Sending binary ");
        Serial.print(sequenceAt * 8);
        Serial.print("+");
        Serial.print(sequenceAtBit);
        Serial.println(" bits");
#endif        
        //sendBinarySequence(sequence, sequenceAt * 8 + sequenceAtBit);
        sendBinarySequenceHw();
        inBinarySequence = false;
      } break;
      default:
        Serial.println("!");
        inBinarySequence = false;
    }
  }
}

void loop() {
  if (inBinarySequence) {
    binarySequenceLoop();
    if (!inBinarySequence) {
      sequenceAt = 0;
      prevSequenceSize = 0;
    }
  } else {
    baseLoop();
  }
}

// time routines extracted from: http://www.jbox.dk/sanos/source/lib/time.c.html
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.  
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
// SUCH DAMAGE.
// 

// from http://embeddedgurus.com/barr-code/2009/09/binary-literals-in-c/
#define HEX__(n) 0x##n##LU
#define B8__(x) ((x&0x0000000FLU)?1:0) \
+((x&0x000000F0LU)?2:0) \
+((x&0x00000F00LU)?4:0) \
+((x&0x0000F000LU)?8:0) \
+((x&0x000F0000LU)?16:0) \
+((x&0x00F00000LU)?32:0) \
+((x&0x0F000000LU)?64:0) \
+((x&0xF0000000LU)?128:0)

// User-visible Macros
#define B8(d) ((uint8_t)B8__(HEX__(d)))

/* Time manipulation code */

struct tm {
  int tm_year;
  int tm_yday;
  int tm_mon;
  int tm_mday;
  int tm_wday;
  int tm_hour;
  int tm_min;
  int tm_sec;
};

#define EPOCH_YR                1970
#define SECS_DAY                (24L * 60L * 60L)
#define LEAPYEAR(year)          (!((year) % 4) && (((year) % 100) || !((year) % 400)))
#define YEARSIZE(year)          (LEAPYEAR(year) ? 366 : 365)
#define FIRSTSUNDAY(timp)       (((timp)->tm_yday - (timp)->tm_wday + 420) % 7)
#define FIRSTDAYOF(timp)        (((timp)->tm_wday - (timp)->tm_yday + 420) % 7)

#define TIME_MAX                2147483647L

#define TZ_OFFSET (3600 * 3)

int _daylight = 0;                  // Non-zero if daylight savings time is used
long _dstbias = 0;                  // Offset for Daylight Saving Time
long _timezone = 0;                 // Difference in seconds between GMT and local time
char *_tzname[2] = {"GMT", "GMT"};  // Standard/daylight savings time zone names

const int yearDays[2][12] = {
  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

struct tm *gmtime_r(const uint32_t time, struct tm *tmbuf) {
  unsigned long dayclock, dayno;
  int year = EPOCH_YR;

  dayclock = (unsigned long) time % SECS_DAY;
  dayno = (unsigned long) time / SECS_DAY;

  tmbuf->tm_sec = dayclock % 60;
  tmbuf->tm_min = (dayclock % 3600) / 60;
  tmbuf->tm_hour = dayclock / 3600;
  tmbuf->tm_wday = (dayno + 4) % 7; // Day 0 was a thursday
  while (dayno >= (unsigned long) YEARSIZE(year)) {
    dayno -= YEARSIZE(year);
    year++;
  }
  tmbuf->tm_year = year;
  tmbuf->tm_yday = dayno;
  tmbuf->tm_mon = 0;
  while (dayno >= (unsigned long) yearDays[LEAPYEAR(year)][tmbuf->tm_mon]) {
    dayno -= yearDays[LEAPYEAR(year)][tmbuf->tm_mon];
    tmbuf->tm_mon++;
  }
  tmbuf->tm_mday = dayno + 1;
  return tmbuf;
}

/* End of time manipulation code */

/* Networking code */ 
#include "etherShield.h"
#include "ETHER_28J60.h"

#define TRANSMIT_TIMESTAMP_P 40
#define NTP_PACKET_SIZE 48

static uint8_t mac[6] = {0x54,0x55,0x58,0x10,0x00,0x24}; 
static uint8_t ip[4] = {192,168,11,60};
static uint16_t port = 80;

static const int bufferSize = 200;
static uint8_t buf[bufferSize];

extern EtherShield es;

static const int ntpPort = 123;

ETHER_28J60 ethernet;

/* End of networking code */

int out = 2;
int in = 3;
int debug = 4;

/* Bit sequence sending declarations */

//uint8_t setHHMM[] = { 32, 117, 103, 0, 248, 7, 128, 126, 1, 143, 254, 192, 255 };
uint8_t setHHMM[] = { 4, 174, 230, 0, 31, 224, 1, 126, 128, 241, 127, 3, 255 };

uint8_t bitsOfDigit[10] = {
  B8(00000001),
  B8(01001111),
  B8(00010010),
  B8(00000110),
  B8(01001100),
  B8(00100100),
  B8(00100000),
  B8(00001111),
  B8(00000000),
  B8(00000100)
};

volatile uint8_t* sequence;

/* End of bit sequence sending declarations */

/* Timer interrupt code */
volatile int writeBitsLeft = 0;
volatile int writeCurBit = 0;
volatile int writeCurByte = 0;

static const int prescaler = 1;
static const double systemHz = 16000000;
static const double bitLength = 52.0 / 1000000.0;
static const unsigned int finetuning = 50; // fine-tuned with an oscilloscope
static const unsigned int timerPreload = 65536 - systemHz / prescaler / (1 / bitLength) + finetuning;

void setupTimer()
{
