/***********************************************************

	pic18timer.c

	Version 1.00: 2009/10/12

	Copyright (C) 2008-2009, MicroFan Div., PeopleMedia, Inc.
	All rights reserved.

***********************************************************/

#include "picsys18.h"
#include <delays.h>

#if defined(USE_USB)
#include "Compiler.h"
#include "USB\usb_function_cdc.h"
#endif

#if defined(PICSYS18_XBEE) || defined(PIC_DEV_2420RL)
void _uxRxPolling(void) ;
#endif

#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
	#define REMAPPED_RESET_VECTOR_ADDRESS			0x1000
	#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x1008
	#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x1018
#else	
	#define REMAPPED_RESET_VECTOR_ADDRESS			0x00
	#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x08
	#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x18
#endif
	
#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)
extern void _startup (void);        // See c018i.c in your C18 compiler dir
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void)
{
    _asm goto _startup _endasm
}
#endif


void isr_high() ;
void isr_low() ;

#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void Remapped_High_ISR (void)
{
     _asm goto isr_high _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
void Remapped_Low_ISR (void)
{
     _asm goto isr_low _endasm
}

#if defined(PROGRAMMABLE_WITH_USB_HID_BOOTLOADER)

#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void High_ISR (void)
{
     _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}

#pragma code LOW_INTERRUPT_VECTOR = 0x18
void Low_ISR (void)
{
     _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
#endif

#pragma code
	

/***********************************************************
	計時処理
***********************************************************/

static unsigned long millisec = 0 ;


unsigned long
millis()
{
	unsigned long t ;
	
	noInterrupts() ;
	t = millisec ;
	interrupts() ;
	
	return t ;
}


void
delayMicroseconds(unsigned int t)
{
	if (t == 1) {
#if F_CPU >= 40MHz
		Delay10TCY() ;
#elif F_CPU >= 32MHz
		Delay1TCY() ; Delay1TCY() ;
		Delay1TCY() ; Delay1TCY() ;
#else
		Delay1TCY() ; Delay1TCY() ;
#endif
	} else {
		t *= (unsigned int)(F_CPU/(4MHz)) ; // マシンサイクル数への変換

		while (t > 2000) {
			Delay1KTCYx(2) ;
			t -= 2000 ;
		}

		while (t > 200) {
			Delay100TCYx(2) ;
			t -= 200 ;
		}

		t >>= 3 ;

		if (t != 0)
			Delay10TCYx(t) ;
	}
}


void
delayMilliseconds(unsigned int t)
{
	unsigned long s ;

	s = millis() + t ;

	while (millis() <= s) {
		Sleep() ; // Idleです
	}	

	return ;
}


/***********************************************************
	タイマー割り込み関係
***********************************************************/

void
TIMER2_init()
{
	PR2 = (125 - 1) ;

	/* プリスケーラーを1/4に設定、ポストスケーラを。。。 */
	/* TCY / プリスケーラ / PR2 / HEART_BEAT */
	T2CON = 0b00000001 | (((BYTE)(F_CPU / 4 / 4 / 125 / HEART_BEAT) - 1) << 3) ;

	RCONbits.IPEN = 1 ;	// 優先順位割り込み使用

	IPR1bits.TMR2IP = 0 ;	// 低レベル
	PIR1bits.TMR2IF = 0 ;
	PIE1bits.TMR2IE = 1 ;
	INTCONbits.GIEL = 1 ;
	INTCONbits.GIEH = 1 ;

	T2CONbits.TMR2ON = 1 ;
}


/************************************************/

void
TIMER3_setup(int v)
{
	unsigned int cnt ;

	cnt = SERVO_NEUTRAL + v * (SERVO_MINMAX/100) ;
	cnt = 65536 - (cnt * (unsigned int)(F_CPU/(4MHz))) ;

//	T3CON = 0b00000000 ; // 初期値

	TMR3H = cnt >> 8 ;
	TMR3L = cnt & 0xff ;

	IPR2bits.TMR3IP = 1 ;	// 高レベル
	PIR2bits.TMR3IF = 0 ;
	PIE2bits.TMR3IE = 1 ;
	INTCONbits.GIEH = 1 ;
}


/***********************************************************
	割り込みハンドラ
***********************************************************/

extern BYTE _usbEnable ;

extern BYTE _beepPin ;
extern BYTE _beepValue ;

extern BYTE _pwmPin[]  ;
extern BYTE _pwmValue[] ;

extern BYTE _servoPin[]  ;
extern BYTE _servoDisable ;
extern int _servoValue[] ;
extern int _servoMin[] ;
extern int _servoMax[] ;

static BYTE __servoNum ;


/* サーボパルス終了用割り込みハンドラ */
#pragma interrupt isr_high
void
isr_high()
{	
//	if (PIR2bits.TMR3IF && PIE2bits.TMR3IE) {
	if (PIR2bits.TMR3IF) {
		/* ServoのPWMパルス終了 */
		isr_bitOut(_servoPin[__servoNum], LOW) ;
		/* 割り当てが解除されていればその処理 */
		if (_servoDisable & BIT(__servoNum)) {
			_servoPin[__servoNum] = NO_ASSIGN ;
			_servoDisable &= ~BIT(__servoNum) ;
		}

		/* TIMER3はいったんお休み */
		T3CONbits.TMR3ON = 0 ;
		PIE2bits.TMR3IE = 0 ;
		PIR2bits.TMR3IF = 0 ;
	}
}


BYTE _refreshMask ;
BYTE _refreshDevice ;

/* 割り込みハンドラ */
#pragma interruptlow isr_low // save=section(".tmpdata")
void
isr_low()
{
	static BYTE n ;
	static BYTE sv = 0 ; // サーボパルスのスタートタイミング管理
	BYTE i, id ;

	if (PIR1bits.TMR2IF && PIE1bits.TMR2IE) {	// 一定間隔の割り込み
		PIR1bits.TMR2IF = 0 ;

		/* 音がにごらないようにできるだけ早く */
		if (_beepPin != NO_ASSIGN)
			isr_bitOut(_beepPin, n & BIT(8 - _beepValue)) ;

#if defined(PICSYS18_XBEE) || defined(PIC_DEV_2420RL)
	_uxRxPolling() ;
#endif

		n++ ;

#if HEART_BEAT == 2KHz
		if (n & 1) {
			millisec++ ;
		}
#else
		millisec++ ;
#endif
		sv++ ;

		if (sv >= 20*(HEART_BEAT/(1KHz)))	// 20msで１周期
			sv = 0 ;

		i = n & (BIT(4) * (HEART_BEAT/(1KHz)) - 1) ;

		if (_pwmPin[0] != NO_ASSIGN)
			isr_bitOut(_pwmPin[0], _pwmValue[0] > i) ;

		if (_pwmPin[1] != NO_ASSIGN)
			isr_bitOut(_pwmPin[1], _pwmValue[1] > i) ;

		if (_pwmPin[2] != NO_ASSIGN)
			isr_bitOut(_pwmPin[2], _pwmValue[2] > i) ;

		if (_pwmPin[3] != NO_ASSIGN)
			isr_bitOut(_pwmPin[3], _pwmValue[3] > i) ;

		id = NO_ASSIGN ;
		if ((sv == 0*(HEART_BEAT/(1KHz))) && (_servoPin[0] != NO_ASSIGN)) {
			id = 0 ;
		} else if ((sv == 5*(HEART_BEAT/(1KHz))) && (_servoPin[1] != NO_ASSIGN)) {
			id = 1 ;
		} else if ((sv == 10*(HEART_BEAT/(1KHz))) && (_servoPin[2] != NO_ASSIGN)) {
			id = 2 ;
		} else if ((sv == 15*(HEART_BEAT/(1KHz))) && (_servoPin[3] != NO_ASSIGN)) {
			id = 3 ;
		}

		if (id != NO_ASSIGN) {
			__servoNum = id ;
			TIMER3_setup(_servoValue[id]) ;

			/* タイミング管理：次の２つの処理は割り込みハンドラの処理順序とあわせる */
			T3CONbits.TMR3ON = 1 ;	// こっちが先
#if F_CPU <= 8MHz
			Delay10TCYx(8) ;
#endif
			isr_bitOut(_servoPin[id], HIGH) ; // こっちは後
		}

		/* ダイナミック表示を更新 */
#if defined(USE_SEG7)
		if ((_refreshDevice & REFRESH_SEG7)
			& ((n & (BIT(HEART_BEAT/(1KHz)+1) - 1)) == 0))
			isr_SEG7_update() ;	// 250Hz:1Cycle-62.5Hz
#elif defined(USE_DML)
		if ((_refreshDevice & REFRESH_DML)
			& ((n & (BIT(HEART_BEAT/(1KHz)) - 1)) == 0))
			isr_DML_update() ;	// 500Hz:1Cycle-62.5Hz
#elif defined(PIC_DEV_2550URL)
		if ((n & (BIT(HEART_BEAT/(1KHz)+1) - 1)) == 0)
			isr_SW_update() ;	// 250Hz
#endif
	}

#if defined(USE_USB)
	if (PIR2bits.USBIF && PIE2bits.USBIE) {
		USBDeviceTasks();
	}
#endif

#if 0
	if (INTCONbits.TMR0IF && INTCONbits.TMR0IE) {	// TIMER0からの割り込み		
//		isrFunc() ;

		INTCONbits.TMR0IF = 0 ;
	}
#endif
}
