/* flaneth - flash and ethernet
   Copyright (C) 2007-2012 Stefan Schuermans <stefan@schuermans.info>
   Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html
   a BlinkenArea project - http://www.blinkenarea.org/ */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>

#include "arp.h"
#include "cf.h"
#include "dhcp.h"
#include "ip.h"
#include "random.h"
#include "rtl8019.h"
#include "status.h"
#include "tcp.h"
#include "timing.h"
#include "udp.h"

// global timer in ms
volatile unsigned long TimingMs = 0;

// 2ms tick counter to generate 20ms ticks
volatile unsigned char Timing2_10 = 0;

// flag set every 20ms to indicate execution of 20ms ticks
volatile unsigned char Timing20Flag = 0;

// wrapping around 20ms tick counter
unsigned char Timing20 = 0;

// 20ms tick counter to generate 200ms ticks
unsigned char Timing20_10 = 0;

// 2ms interrupt (timer 0 compare match)
SIGNAL(SIG_OUTPUT_COMPARE0)
{
  // advance global timer
  TimingMs += 2;
  // set flag every 20ms
  Timing2_10++;
  if (Timing2_10 >= 10) {
    Timing2_10 = 0;
    Timing20Flag = 1;
  }
}

// initialize
void TimingInit(void)   // (extern)
{
  // configure timer 0 to 2ms interval
  TCCR0 = 0 << FOC0 | 1 << WGM01 | 0 << WGM00 | // count to OCR0
      0 << COM01 | 0 << COM00 | // no waveform generation
      1 << CS02 | 1 << CS01 | 0 << CS00;        // 1/256 of sysclock (16MHz)
                                                // -> increment every 16us
  OCR0 = 124;   // count to 124 -> 2ms interval

  // enable timer 0 compare match interrupt
  TIMSK |= 1 << OCIE0;

  // configure timer 1 to count cycles
  TCCR1A = 0 << WGM11 | 0 << WGM10;           // normal mode
  TCCR1B = 0 << WGM13 | 0 << WGM12 |          // normale mode
           0 << CS12 | 0 << CS11 | 1 << CS10; // no prescaler
}

// get time in milliseconds
void TimingGetMs(unsigned long *ms) // (extern)
{
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    *ms = TimingMs;
  }
}

// provide curent time stamp as entropy to random number generator
void TimingEntropy(void)        // (extern)
{
  unsigned short timestamp = TCNT1;
  RandomProvideEntropy((unsigned char)timestamp);
  RandomProvideEntropy((unsigned char)(timestamp >> 8));
}

// provide curent 20ms tick counter as entropy to random number generator
void Timing20Entropy(void)      // (extern)
{
  RandomProvideEntropy(Timing20);
}

// task function to do the work - call from main loop
void TimingTask(void)   // (extern)
{
  // 20ms not elapsed
  if (!Timing20Flag)
    return;
  Timing20Flag = 0;

  // call 20ms tick functions
  CfTick20();

  // generate 200ms steps
  Timing20_10++;
  if (Timing20_10 >= 10)
    Timing20_10 = 0;

  // call 200ms tick functions at different times
  switch (Timing20_10) {
  case 1:
    ArpTick200();
    break;
  case 3:
    IpTick200();
    break;
  case 5:
    //RtlTick200();
    break;
  case 6:
    StatusTick200();
    break;
  case 7:
    TcpTick200();
    break;
  case 8:
    UdpTick200();
    break;
  case 9:
    DhcpTick200();
    break;
  }
}
