/*
 * naked_int_test.c
 *
 *  Created on: Oct 20, 2010
 *      Author: RAM0605
 */
#include <stdio.h>
#include <stdarg.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/neutrino.h>
#include <sys/siginfo.h>
#include <hw/inout.h>
#include <unistd.h>
#include <pthread.h>

#define Sleep(x) usleep(x*1000)
typedef int HANDLE;

int intId;
struct sigevent event;
uintptr_t stIoCtl;
uintptr_t stIoLoMap;
uintptr_t stIoHiMap;
int max_pri;

#define IRQ 5
//#define __PRI 244
#define __PRI (max_pri - 11)

#define MYSCHED SCHED_RR

typedef void *(*pth_func)(void *);
int _beginthread (void (*__func) (void *), unsigned stack, void *arg)
{
	pthread_attr_t attr;
	pthread_attr_init( &attr );
	pthread_attr_setstacksize(&attr, stack);
	pthread_attr_setschedpolicy(&attr, MYSCHED);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED );
	int id = pthread_create( NULL, &attr, (pth_func)(__func), arg);
	return id;
}

void SetThreadPriority(HANDLE id, int priority)
{
	struct sched_param param;
	int policy;
	pthread_getschedparam(id, &policy, &param);
	param.sched_priority = priority;
	pthread_setschedparam(id, policy, &param);
}

/* interrupt generator thread */
void gen_thread (void *arg) {
	ThreadCtl( _NTO_TCTL_IO, 0 );
	/* generate interrupts */
	while (1) {
		Sleep(1);
		out8(stIoHiMap, 0xFF); //set interrupt
	}
}
/* low priority thread */
void low_thread (void *arg) {
	int siFd;
	char acBuf[65536];

	for(;;Sleep(50)){
		siFd = open("/tmp/tmp", O_RDWR |O_CREAT |O_TRUNC );
		if (siFd) {
			write(siFd, acBuf, sizeof(acBuf));
			write(siFd, acBuf, sizeof(acBuf));
			write(siFd, acBuf, sizeof(acBuf));
			write(siFd, acBuf, sizeof(acBuf));
			close(siFd);
		}
	}
}

/* interrupt */
const struct sigevent* ISR(void *pstIoLoMap, int len)
{
	InterruptMask (IRQ, intId);
	out8(*((uintptr_t *)pstIoLoMap), 0xFF);//signal start

	return &event;
}

/* high priority thread */
void int_thread (void *arg)
{

	SIGEV_INTR_INIT( &event );
	ThreadCtl( _NTO_TCTL_IO, 0 );
	intId=InterruptAttach (IRQ, ISR, (void *)&stIoLoMap, sizeof(stIoLoMap), 0);

    while (1)
    {
        InterruptWait (NULL, NULL);
        out8(stIoHiMap, 0);//Clear IRQ
        out8(stIoLoMap, 0);//signal finished.
    	InterruptUnmask(IRQ, intId);
    }
}

int main(int argc, char *argv[])
{
	ThreadCtl( _NTO_TCTL_IO, 0 );
	stIoCtl = mmap_device_io(16, 0x98); //GPIO control
	stIoLoMap = mmap_device_io(8, 0x78); //GPIO 0 data
	stIoHiMap = mmap_device_io(8, 0x79); //GPIO 1 data
	out16(stIoCtl, 0xFFFF); // set all to output
    out8(stIoLoMap, 0);
    out8(stIoHiMap, 0);

    max_pri = sched_get_priority_max(MYSCHED);

	/* start low priority thread */
//	SetThreadPriority((HANDLE)_beginthread(low_thread, 250000, NULL), 1+__PRI);

	/* start high priority thread */
	SetThreadPriority((HANDLE)_beginthread(int_thread, 25000, NULL), 10+__PRI);

	/* start interrupt generator thread */
	SetThreadPriority((HANDLE)_beginthread(gen_thread, 25000, NULL), 11+__PRI);

	/* idle */
	for(;;)
		Sleep(1000);

	return 0;
}
