//-------------------------------------------------
//          TestSuite: Yield
//-------------------------------------------------

#include "lcd.h"
#include "util.h"
#include "os_core.h"
#include "os_scheduler.h"
#include "os_memory.h"

#include <avr/interrupt.h>

#define DELAY (999 + 1ul)

#define BASE 2

typedef unsigned long volatile Iterations;

unsigned logBase(unsigned long base, unsigned long value) {
  if (base <= 1)
    return 0;
  unsigned result = 0;
  for (; value; value /= base)
    result++;
  return result;
}

void loop(bool yield, Iterations* iterations) {
  for (;;) {
    unsigned long volatile i = 100*DELAY;
    while (i--) {
      if (yield) {
        os_yield();
      } else {
        unsigned int volatile j = 20; // estimation of os_yield
        while (j--)
          asm volatile ("nop");
      }
      cli();
      ++*iterations;
      sei(); // we positively KNOW the I-Flag was off!
    }
  }
}


Iterations iterations1 = 0, iterations2 = 0;

PROGRAM(1,AUTOSTART) {
  loop(false, &iterations1);
}

PROGRAM(2,AUTOSTART) {
  loop(true, &iterations2);
}

PROGRAM(3,AUTOSTART) {
  os_setSchedulingStrategy(OS_SS_EVEN);
  for (;;) {
    lcd_clear();
    lcd_writeProgString(PSTR("NoYld/Yld-Ratio:"));
    lcd_writeDec(BASE);
    lcd_writeChar('^');
    lcd_writeDec(logBase(BASE, iterations1));
    lcd_writeChar('/');
    lcd_writeDec(BASE);
    lcd_writeChar('^');
    lcd_writeDec(logBase(BASE, iterations2));
    Iterations i1, i2;
    do {
      i1 = iterations1;
      i2 = iterations2;
      lcd_goto(2,11);
      lcd_writeChar('=');
      if (iterations1 >= iterations2)
        lcd_writeDec(iterations1 / iterations2);
      else {
        lcd_writeChar('1');
        lcd_writeChar('/');
        lcd_writeDec(iterations2 / iterations1);
      }
      while (i1 == iterations1 && i2 == iterations2);
    } while (logBase(BASE, i1) == logBase(BASE, iterations1) && logBase(BASE, i2) == logBase(BASE, iterations2));
  }
}
