/* Copyright (c) 2008, Daniel Willmann <daniel@totalueberwachung.de>
 * 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. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 *
 * This file is part of the Contiki OS
 *
 *
 */

#include "contiki.h"
#include "dev/rs232.h"

#include <avr/io.h>
#include <stdio.h>
#include <dev/watchdog.h>
#include <avr/pgmspace.h>

#define PRINTA(FORMAT,args...) printf_P(PSTR(FORMAT),##args)
#define DEBUG 0
#if DEBUG
#define PRINTD PRINTA
#else
#define PRINTD(...)
#endif

/* Test rtimers, also stack monitor and time stamps */
#define TESTRTIMER 1
#if TESTRTIMER
#define STAMPS 30
#define STACKMONITOR 128

uint8_t rtimerflag=1;
uint16_t rtime;
struct rtimer rt;
void rtimercycle(void) {rtimerflag=1;}
#endif /* TESTRTIMER */

#if defined (__AVR_ATmega8__)
FUSES =
  {
    .low = 0xe0,
    .high = 0xd9,
  };
#elif defined (__AVR_ATmega16__)
FUSES =
  {
    .low = 0xe0,
    .high = 0x99,
  };
#elif defined (__AVR_ATmega644__)
FUSES =
  {
    .low = 0xe0,
    .high = 0x99,
    .extended = 0xff,
  };

//MCU=atmega8515
//MCU=atmega328p
//MCU=atmega32
#endif


PROCESS(led_process, "LED process");
PROCESS_THREAD(led_process, ev, data)
{
  static struct etimer etimer;

  PROCESS_BEGIN();
  while (1) {
    PRINTD("LED1\r\n");
    PORTB |= (1<<PB1);
    PORTD |= (1<<PD3);
    etimer_set(&etimer, CLOCK_SECOND*0.5);
    PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
    PORTB &= ~(1<<PB1);
    PORTD &= ~(1<<PD3);
    etimer_set(&etimer, CLOCK_SECOND*0.5);
    PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
  }

  PROCESS_END();
}

PROCESS(led2_process, "LED process");
PROCESS_THREAD(led2_process, ev, data)
{
  static struct etimer etimer;

  PROCESS_BEGIN();
  while (1) {
    PRINTD("LED2\r\n");
    PORTB |= (1<<PB0);
    PORTD |= (1<<PD2);
    etimer_set(&etimer, CLOCK_SECOND*0.3);
    PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
    PORTB &= ~(1<<PB0);
    PORTD &= ~(1<<PD2);
    etimer_set(&etimer, CLOCK_SECOND*0.3);
    PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
  }

  PROCESS_END();
}

void led_init()
{
  DDRB |= (1<<PB1)|(1<<PB0);
  PORTB &= ~((1<<PB1)|(1<<PB0));
  DDRD |= (1<<PD2)|(1<<PD3);
  PORTD &= ~((1<<PD2)|(1<<PD3));
}

/* These can also be explicitly started below */
PROCINIT(&etimer_process, &led_process, &led2_process);

void
initialize(void)
{
  watchdog_init();
  watchdog_start();
  
#if STACKMONITOR
  /* Simple stack pointer highwater monitor. Checks for magic numbers in the main
   * loop. In conjuction with TESTRTIMER, never-used stack will be printed
   * every STACKMONITOR seconds.
   */
{
extern uint16_t __bss_end;
uint16_t p=(uint16_t)&__bss_end;
    do {
      *(uint16_t *)p = 0x4242;
      p+=4;
    } while (p<SP-4); //don't overwrite our own stack
}
#endif

  /* rtimers needed for radio cycling */
  rtimer_init();

  rs232_init(RS232_PORT_0, BAUD_RATE(38400), USART_DATA_BITS_8 | USART_PARITY_NONE | USART_STOP_BITS_1);
  rs232_redirect_stdout(RS232_PORT_0);

  clock_init();
  sei();

  /* Initialize drivers and event kernel */
  process_init();
 
  led_init();

#if 0
  procinit_init();
#else
  process_start(&etimer_process, NULL);
  process_start(&led_process, NULL);
  process_start(&led2_process, NULL);
#endif

  PRINTA(CONTIKI_VERSION_STRING " started\r\n");

  /* Comment this out if autostart_processes not defined at link */
  /* Note AUTOSTART_PROCESSES(...) is only effective in the .co module */
  autostart_start(autostart_processes);
  
}
int
main(void)
{
  initialize();
  
  while(1) {
    process_run();
	
#if TESTRTIMER
/* Timeout can be increased up to 8 seconds maximum.
 * A one second cycle is convenient for triggering the various debug printouts.
 * The triggers are staggered to avoid printing everything at once.
 */
    if (rtimerflag) {
      rtimer_set(&rt, RTIMER_NOW()+ RTIMER_ARCH_SECOND*1UL, 1,(void *) rtimercycle, NULL);
      rtimerflag=0;

#if STAMPS
if ((rtime%STAMPS)==0) {
  PRINTA("%us ",rtime);
}
#endif
      rtime+=1;

#if STACKMONITOR
if ((rtime%STACKMONITOR)==3) {
  extern uint16_t __bss_end;
  uint16_t p=(uint16_t)&__bss_end;
  do {
    if (*(uint16_t *)p != 0x4242) {
      PRINTA("Never-used stack > %d bytes\n",p-(uint16_t)&__bss_end);
      break;
    }
    p+=4;
  } while (p<RAMEND-4);
}
#endif

    }
#endif /* TESTRTIMER */

  }

  return 0;
}