//-------------------------------------------------
//          TestSuite: Strategies
//-------------------------------------------------

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

#include <avr/interrupt.h>
#include <stdint.h>
#include <stdlib.h>

#define DELAY 100

#define DRIVER intHeap


PROGRAM(1, AUTOSTART) {
  struct {
    AllocStrategy strat;
    char name;
  } cycle[] = {
    {
      .strat = OS_MEM_FIRST,
      .name = 'f'
    }, {
      .strat = OS_MEM_NEXT,
      .name = 'n'
    }, {
      .strat = OS_MEM_BEST,
      .name = 'b'
    }, {
      .strat = OS_MEM_WORST,
      .name = 'w'
    }
  };
  uint8_t lastStrategy;

  MemAddr p[6];
  uint16_t s[4];

  os_enterCriticalSection();
  lcd_clear();
  lcd_writeProgString(PSTR("Check strategy.."));
  delayMs(5*DELAY);
  lcd_clear();
  os_leaveCriticalSection();

  srand(TCNT0*TCNT1);

  for (lastStrategy = 0; ; lastStrategy = (lastStrategy+1)%(sizeof(cycle)/sizeof(*cycle))) {
    uint8_t iterations;
    lcd_clear();
    lcd_writeProgString(PSTR("Changing strat.\nto "));
    lcd_writeChar(cycle[lastStrategy].name);
    os_setAllocationStrategy(DRIVER, cycle[lastStrategy].strat);
    delayMs(5*DELAY);
    lcd_clear();
    for (iterations = 0; iterations < 8; iterations++) {

      // generate new sizes with s0 > s2
      // s1, s3 > 0. but irrelevant, since they will be used as separators
      s[2] = (rand()%(os_getUseSize(DRIVER)/5)) + 9;
      s[0] = s[2] + (rand()%(s[2] - 8)) + 1;
      s[1] = 1;
      s[3] = 1;

      uint8_t i;
      // allocate all directly after each other
      for (i = 0; i < 4; i++) {
        p[i] = os_malloc(DRIVER, s[i]);
      }
      // free s0 and s2. we got 3 blocks: s0 big,  s2 small  rest huge
      for (i = 0; i < 4; i += 2) {
        os_free(DRIVER, p[i]+((TCNT0)%s[i]));
      }

      /* we allocate, and directly free s2 two times
       * for NextFit we should get different addresses
       * for FirstFit, both addresses are equal to old s0
       * for BestFit, both addresses are equal to old s2
       * for WorstFit we get the first byte of the rest memory
       * otherwise we found an error ;)
       */
      for (i = 4; i <= 5; i++) {
        p[i] = os_malloc(DRIVER, s[2]);
        os_free(DRIVER, p[i]);
      }

      // its time to check what we got
      lcd_writeChar(cycle[lastStrategy].name);
      lcd_writeChar(':');
      if (p[4] != p[5])
        lcd_writeChar('n');
      else if (p[4] == p[0])
        lcd_writeChar('f');
      else if (p[2] == p[4])
        lcd_writeChar('b');
      else if (p[4] == p[3]+s[3])
        lcd_writeChar('w');
      else
        lcd_writeChar('e');
      lcd_writeChar(';');

      // free all allocated chunks
      for (i = 1; i < 4; i +=2) {
        os_free(DRIVER, p[i] + ((TCNT1)%s[i]));
      }
      delayMs(2*DELAY);
    }
    delayMs(15*DELAY);
  }
}
