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

	picsys18.c

	Version 1.00: 2009/10/10

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

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

#include "picsys18.h"


/***********************************************************
	CONFIG設定
***********************************************************/

#if defined(__18F2420) || defined(__18F2520)|| defined(__18F2620)

#ifdef XTAL_OSC
#if XTAL_OSC >= 32MHz
#pragma config OSC = HSPLL
#else
#pragma config OSC = HS
#endif

#else
#pragma config OSC = INTIO67
#endif

#pragma config MCLRE = OFF
#pragma config WDT = OFF
#pragma config PBADEN = ON
#pragma config LVP = OFF

#pragma config BOREN = OFF
#pragma config BORV = 2		// 1:4.3V,2:2.8V

#pragma config PWRT = ON
#pragma config FCMEN = ON

#elif defined(__18F4550) || defined(__18F2550) || defined(__18F2553)

#pragma config FOSC = HSPLL_HS
#pragma config PLLDIV = 2	// 2:8MHz, 5:20MHz

#if F_CPU == 48MHz
#pragma config CPUDIV = OSC1_PLL2
#elif F_CPU == 32MHz
#pragma config CPUDIV = OSC2_PLL3
#elif F_CPU == 24MHz
#pragma config CPUDIV = OSC3_PLL4
#elif F_CPU == 16MHz
#pragma config CPUDIV = OSC4_PLL6
#endif

#pragma config USBDIV = 2

#pragma config MCLRE = ON
#pragma config WDT = OFF
#pragma config PBADEN = ON
#pragma config LVP = OFF
#pragma config BOR = ON
#pragma config BORV = 2	// 1:4.33, 2:2.79, 3:2.05

#pragma config XINST = OFF


#elif defined(__18F26J50) || defined(__18F25J50) || defined(__18F24J50)

#pragma config XINST = OFF

#pragma config OSC = INTOSCPLL
#pragma config PLLDIV = 2	// 2:8MHz, 5:20MHz

#if F_CPU == 48MHz
#pragma config CPUDIV = OSC1
#elif F_CPU == 24MHz
#pragma config CPUDIV = OSC2_PLL2
#elif F_CPU == 16MHz
#pragma config CPUDIV = OSC3_PLL3
#elif F_CPU == 8MHz
#pragma config CPUDIV = OSC4_PLL6
#endif

#endif


/***********************************************************
	グローバル変数定義
***********************************************************/

#if defined(__18F40PIN)
static rom BYTE _adMap[] = {RA(0), RA(1), RA(2), RA(3), RA(5), RE(0), RE(1), RE(2),
		RB(2), RB(3), RB(1), RB(4), RB(0)} ;
#elif defined(__18F28PIN)
static rom BYTE _adMap[] = {RA(0), RA(1), RA(2), RA(3), RA(5), NO_ASSIGN, NO_ASSIGN, NO_ASSIGN,
		RB(2), RB(3), RB(1), RB(4), RB(0)} ;
#elif defined(__18FJ28PIN)
#define	__NEW_AD
static rom BYTE _adMap[] = {RA(0), RA(1), RA(2), RA(3), RA(5), NO_ASSIGN, NO_ASSIGN, NO_ASSIGN,
		RB(2), RB(3), RB(1), RC(2), RB(0)} ;
#elif defined(__18F14K50)
static rom BYTE _adMap[] = {NO_ASSIGN, NO_ASSIGN, NO_ASSIGN, RA(4), RC(0), RC(1), RC(2), RC(3),
		RC(6), RC(7), RB(4), RB(5)} ;
#elif defined(__18F1320)
static rom BYTE _adMap[] = {RA(0), RA(1), RA(2), RA(3), RB(0), RB(1), RB(4)} ;
#endif


BYTE _beepPin = NO_ASSIGN ;
BYTE _beepValue ;

BYTE _pwmPin[4] = {NO_ASSIGN, NO_ASSIGN, NO_ASSIGN, NO_ASSIGN} ;
BYTE _pwmValue[4] ;

BYTE _servoPin[4] = {NO_ASSIGN, NO_ASSIGN, NO_ASSIGN, NO_ASSIGN} ;
BYTE _servoDisable = 0x00 ;
int _servoValue[4] ;
int _servoMin[4] = {-100, -100, -100, -100} ;
int _servoMax[4] = {100, 100, 100, 100} ;


/***********************************************************
	システムの初期化
***********************************************************/

#if defined(USE_USB)
extern BYTE _usbEnable ;

// void USBDeviceTasks(void);
void USBDeviceInit(void);
void USBDeviceAttach(void);
void CDCTxService(void);
void USB_flush(void);
#endif

static void
_initPicsys(void)
{ 
#if defined(__18F2420) || defined(__18F2520)|| defined(__18F2620)
#ifdef INT_OSC
	OSCCON = 0b01110000 ;
#if F_CPU == 32MHz
	OSCTUNEbits.PLLEN = 1 ;
#elif F_CPU == 8MHz
//	OSCTUNEbits.PLLEN = 0 ;
#else
#error 内蔵発信器の周波数指定が適切ではありません
#endif
#endif
#endif
#if defined(__18F26J50) || defined(__18F25J50)|| defined(__18F24J50)
	OSCTUNEbits.PLLEN = 1 ;
#endif

#if defined(__18F46J50)
    {
        unsigned int pll_startup_counter = 600;
        OSCTUNEbits.PLLEN = 1;  //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
        while(pll_startup_counter--);
    }
#endif

	/* アナログ入力をデジタル入力に */
//	ADCON1 = 0x0f ;

	/* IDLEモードを利用する準備 */
	OSCCONbits.IDLEN = 1 ;

	/* SW入力にプルアップを付ける */
#if defined(__18F14K50)
	INTCON2bits.RABPU = 0 ;
#elif !(defined(__18F26J50) || defined(__18F25J50)|| defined(__18F24J50))
	INTCON2bits.RBPU = 0 ;
#endif

//	TIMER0_init() ;
	TIMER2_init() ;
}


/***********************************************************
	メイン関数
***********************************************************/

void
main(void)
{
	_initPicsys() ;
#if defined(PIC_DEV_2550URL)
	SW_init() ;
#endif

	setup() ;

	for (;;) {
#if defined(USE_USB)
//		USBDeviceTasks() ;
        if (_usbEnable && USB_attached())
            CDCTxService();
#endif
   		loop() ;
   		
#if defined(USE_USB)
        if (_usbEnable && USB_attached())
	   		USB_flush() ;
#endif
	}
}


/***********************************************************
	スイッチの処理
***********************************************************/

#if defined(PIC_DEV_2550URL)
static BYTE __sw[6] ;

void
SW_init()
{
	pinMode(SW_ACTIVATE, OUTPUT) ;
	digitalWrite(SW_ACTIVATE, HIGH) ;

	__sw[0] = 0xff ;
	__sw[1] = 0xff ;
	__sw[2] = 0xff ;
	__sw[3] = 0xff ;
	__sw[4] = 0xff ;
	__sw[5] = 0xff ;
}


#if 1
BYTE dataPin, clockPin ; // ダミー

void
isr_SW_update()
{
/*
	OPT_SEG1_TRIS = 1;
	OPT_SEG2_TRIS = 1;
	OPT_SEG3_TRIS = 1;
	OPT_SEG4_TRIS = 1;
	OPT_SR_DAT_TRIS = 1;
*/
	TRISB |= OPT_SW_MASK ;

	OPT_SW_ACTIVATE = 0 ;

	__sw[0] = OPT_SW1 ;
	__sw[1] = OPT_SW2 ;
	__sw[2] = OPT_SW3 ;
	__sw[3] = OPT_SW4 ;
	__sw[4] = OPT_SW5 ;
	__sw[5] = OPT_SW6 ;

	OPT_SW_ACTIVATE = 1 ;
/*
	OPT_SEG1_TRIS = 0;
	OPT_SEG2_TRIS = 0;
	OPT_SEG3_TRIS = 0;
	OPT_SEG4_TRIS = 0;
	OPT_SR_DAT_TRIS = 0;
*/
	TRISB &= ~OPT_SW_MASK ;
}
#else

BYTE dataPin, clockPin ;
#if defined(USE_SEG7)
extern BYTE segDigit[] ;
#elif defined(USE_DML)
extern BYTE ePin ;
extern BYTE dbPin[3] ;
#endif

void
isr_SW_update()
{
	char i ;

#if defined(USE_SEG7)
    for (i = 0; i < NSEG; i++)
		pinMode(segDigit[i], INPUT) ;
#elif defined(USE_DML)
    for (i = 0; i < NSEG-1; i++)
		pinMode(dbPin[i], INPUT) ;
	pinMode(ePin, INPUT) ;
#endif

	pinMode(dataPin, INPUT) ;

	isr_digitalWrite(SW_ACTIVATE, LOW) ;

	__sw[0] = digitalRead(SW1) ;
	__sw[1] = digitalRead(SW2) ;
	__sw[2] = digitalRead(SW3) ;
	__sw[3] = digitalRead(SW4) ;
	__sw[4] = digitalRead(SW5) ;
	__sw[5] = digitalRead(SW6) ;

	isr_digitalWrite(SW_ACTIVATE, HIGH) ;

#if defined(USE_SEG7)
    for (i = 0; i < NSEG; i++)
		pinMode(segDigit[i], OUTPUT) ;
#elif defined(USE_DML)
    for (i = 0; i < NSEG-1; i++)
		pinMode(dbPin[i], OUTPUT) ;
	pinMode(ePin, OUTPUT) ;
#endif
	pinMode(dataPin, OUTPUT) ;
}
#endif

BYTE
SW_read(BYTE n)
{
	return __sw[n] & 1 ;
}

#endif


/***********************************************************
	ピンのI/O処理
***********************************************************/

void
pinMode(BYTE pin, BYTE mode)
{
	char i ;
	BYTE b, pcfg ;
	volatile near unsigned char *p ;

/* 該当ピンの機能を解除 */
	/* アナログ入力の無効化 */
#ifdef __NEW_AD
	for (i = 0; i < sizeof(_adMap)/sizeof(BYTE); i++)
		if (_adMap[i] == pin) {
			if (i > 7) {
				ANCON1 |= BIT(i - 8) ;
			} else {
				ANCON0 |= BIT(i) ;
			}	
			break ;
		}

#else
	for (i = 0; i < sizeof(_adMap)/sizeof(char); i++)
		if (_adMap[i] == pin) {
			pcfg = (~(i) & 0b1111) ;
			if ((ADCON1 & 0b1111) < pcfg) { // アナログピンを縮小
				ADCON1 = pcfg ;
			}
			break ;
		}
#endif

	/* ビープ機能の解除 */
	if (pin == _beepPin) {
		_beepPin = NO_ASSIGN ;
		digitalWrite(pin, LOW) ; // 直流電圧がかからないように
	}

	/* PWM機能の解除 */
	for (i = 0; i < sizeof(_pwmPin)/sizeof(BYTE); i++)
		if (_pwmPin[i] == pin)
			_pwmPin[i] = NO_ASSIGN ;

	/* サーボ機能の解除 */
	for (i = 0; i < sizeof(_servoPin)/sizeof(BYTE); i++)
		if (_servoPin[i] == pin) {
			noInterrupts() ;
			_servoDisable |= BIT(i) ;
			interrupts() ;
		}

/* 該当ピンの機能の再設定を開始 */
	if (mode >= 2) {
		/* 設定だけ；具体的な処理は割り込みサービスルーチンで */
		if (mode == OUT_BEEP) {
			_beepPin = pin ;
			_beepValue = 0 ;
			digitalWrite(pin, LOW) ;
		} else if (isPWM(mode)) {
			_pwmPin[mode & 0b11] = pin ;
			_pwmValue[mode & 0b11] = 0 ;
		} else if (isSERVO(mode)) {
			_servoPin[mode & 0b11] = pin ;
			_servoValue[mode & 0b11] = 0 ;
/*
			_servoMin[mode & 0b11] = -100 ;
			_servoMax[mode & 0b11] = 100 ;
*/
		}

		mode = OUTPUT ;
	}

	/* 指定ピンの対応ビットを算出 */
	b = BIT(pin & 0b00000111) ;
	/* 指定ピンの入出力モードを設定 */
	p = &TRISA + GET_PORT(pin) - 2 ;

	if (mode == OUTPUT) {
		(*p) &= ~b ;
	} else {
		(*p) |= b ;
	}
}


void
__pinMode(BYTE pin, BYTE mode)
{
	BYTE b ;
	volatile near unsigned char *p ;

	/* 指定ピンの対応ビットを算出 */
	b = BIT(pin & 0b00000111) ;
	/* 指定ピンの入出力モードを設定 */
	p = &TRISA + GET_PORT(pin) - 2 ;

	if (mode == OUTPUT) {
		(*p) &= ~b ;
	} else {
		(*p) |= b ;
	}
}


void
digitalWrite(BYTE pin, int value)
{
	char i ;
	BYTE b ;
	volatile near unsigned char *p ;

	/* ビープ割り当てピン */
	if (pin == _beepPin) {
		if (value > 8)
			_beepValue = 8 ;
		else if (value < 0)
			_beepValue = 0 ;
		else
			_beepValue = value ;

		return ;
	}

	/* PWM割り当てピン */
	for (i = 0; i < sizeof(_pwmPin)/sizeof(BYTE); i++)
		if (_pwmPin[i] == pin) {
			if (value < 0)
				value = 0 ;
#if HEART_BEAT == 2000Hz
			if (value >= 100)
				_pwmValue[i] = 32 ;
			else
				_pwmValue[i] = value * 32 / 100 ;
#else
			if (value >= 100)
				_pwmValue[i] = 16 ;
			else
				_pwmValue[i] = value * 16 / 100;
#endif
			return ;
		}

	/* サーボ割り当てピン */
	for (i = 0; i < sizeof(_servoPin)/sizeof(BYTE); i++)
		if (_servoPin[i] == pin) {
			if (value > _servoMax[i])
				_servoValue[i] = _servoMax[i] ;
			else if (value < _servoMin[i])
				_servoValue[i] = _servoMin[i] ;
			else
				_servoValue[i] = value ;

			return ;
		}

	/* 指定ピンの対応ビットを算出 */
	b = BIT(pin & 0b00000111) ;

	/* 指定ピンに値を出力 */
	p = &LATA + GET_PORT(pin) - 2 ;
	if (value == 0) {
		(*p) &= ~b ;
	} else {
		(*p) |= b ;
	}
}


void
bitOut(BYTE pin, int value)
{
	BYTE b ;
	volatile near unsigned char *p ;

	/* 指定ピンの対応ビットを算出 */
	b = BIT(pin & 0b00000111) ;

	/* 指定ピンに値を出力 */
	p = &LATA + GET_PORT(pin) - 2 ;
	if (value == 0) {
		(*p) &= ~b ;
	} else {
		(*p) |= b ;
	}

}


void
isr_bitOut(BYTE pin, int value)
{
	BYTE b ;
	volatile near unsigned char *p ;

	/* 指定ピンの対応ビットを算出 */
	b = BIT(pin & 0b00000111) ;

	/* 指定ピンに値を出力 */
	p = &LATA + GET_PORT(pin) - 2 ;
	if (value == 0) {
		(*p) &= ~b ;
	} else {
		(*p) |= b ;
	}
}


int
digitalRead(BYTE pin)
{
	char i ;
	BYTE b ;
	volatile near unsigned char *p ;

	if (pin == _beepPin)
		return _beepValue ;

	for (i = 0; i < sizeof(_pwmPin)/sizeof(BYTE); i++)
		if (_pwmPin[i] == pin) {
#if HEART_BEAT == 2000Hz
			if (_pwmValue[i] == 32)
				return 100 ;
			return _pwmValue[i] * 100 / 32 ;
#else
			if (_pwmValue[i] == 16)
				return 100 ;
			return _pwmValue[i] * 100 / 16 ;
#endif
		}

	for (i = 0; i < sizeof(_servoPin)/sizeof(BYTE); i++)
		if (_servoPin[i] == pin)
			return _servoValue[i] ;

	/* 指定ピンが属するポートの読み出し */
	switch (pin >> 3) {
#if defined(PIC_DEV_2550URL)
		/* 仮想スイッチ */
		case ID_VSW: // PORTE
			return __sw[(pin & 0b00000111)] ? 1 : 0 ;
			break ;		
#endif
		default:
			p = &PORTA + GET_PORT(pin) - 2 ;
			b = *p ;
			break ;
	}

	/* 指定ピンの入力値を取得 */
	return 1 & (b >> (pin & 0b00000111)) ;
}


/***********************************************************
	アナログピンのI/O処理
***********************************************************/

/* 暫定処理：今後大きく変える予定 */
void
analogWrite(BYTE pin, int value)
{
	char i ;

	if (pin == _beepPin) {
		if (value > 8)
			_beepValue = 8 ;
		else if (value < 0)
			_beepValue = 0 ;
		else
			_beepValue = value ;

		return ;
	}

	for (i = 0; i < sizeof(_pwmPin)/sizeof(BYTE); i++)
		if (_pwmPin[i] == pin) {
#if HEART_BEAT == 2000Hz
			_pwmValue[i] = (value >> 3) & 0b11111 ;
#else
			_pwmValue[i] = (value >> 4) & 0b1111 ;
#endif
			return ;
		}

	for (i = 0; i < sizeof(_servoPin)/sizeof(BYTE); i++)
		if (_servoPin[i] == pin) {
			if (value > _servoMax[i])
				_servoValue[i] = _servoMax[i] ;
			else if (value < _servoMin[i])
				_servoValue[i] = _servoMin[i] ;
			else
				_servoValue[i] = value ;

			return ;
		}
}


static BYTE _vref = 0 ;

int
analogRead(BYTE pin)
{
	int v ;
	BYTE pcfg ;

	/* アナログピン */
	if (!isAN(pin))
		return 0 ;

	/* 有効なアナログピン？ */
	if (_adMap[pin] == NO_ASSIGN)
		return 0 ;

	/* アナログピンをハイインピーダンスに */
	pinMode(_adMap[pin], INPUT) ;

	// CHS, ADON
	ADCON0 = 0b00000001 | (pin << 2) ;

	/* 該当のアナログピンを有効化 */
#ifdef __NEW_AD
	if (pin > 7) {
		ANCON1 &= ~BIT(pin - 8) ;
	} else {
		ANCON0 &= ~BIT(pin) ;
	}	

	ADCON0bits.VCFG0 = _vref ? 1 : 0 ;

//	ADCON1bits.ADFM = 1 ;
	ADCON1 = 0b10110110 ;
#else
	pcfg = (~(pin + 1) & 0b1111) ;
	if ((ADCON1 & 0b1111) > pcfg) { // アナログピンを拡張
		ADCON1 = pcfg | _vref ;
	} else { // すでに拡張されている中のピン
		ADCON1bits.VCFG0 = _vref ? 1 : 0 ;
	}
	// ADFM, ACQT, ADCS
//	ADCON2bits.ADFM = 1 ;
	ADCON2 = 0b10110110 ;
#endif

	ADCON0bits.GO = 1 ;

	while (ADCON0bits.NOT_DONE)
		;

	/* 自動プロモーションしないのでシフト前にキャストが必要：オプションで変更できる */
	v = (((int)ADRESH) << 8) + ADRESL ;

	ADCON0 = 0 ;

	return v ;
}


void
analogReference(BYTE type)
{
#if !defined(__18F14K50)
	pinMode(_adMap[AN(3)], INPUT) ;
#else
	pinMode(_adMap[AN(4)], INPUT) ;
#endif

	if (type == DEFAULT)
		_vref = 0 ;
	else if (type == EXTERNAL)
		_vref = 0b00010000 ;
}


/***********************************************************
	シリアルデータ出力処理
***********************************************************/

#ifdef	OPTIMIZE

void
isr_optShiftOut(BYTE order, BYTE value)
{
	BYTE b, i, v ;

	for (i = 0; i < 8; i++)  {
		v = value & ((order == LSBFIRST) ? 1 : 0b10000000) ;

		OPT_SR_DAT = v ? 1 : 0 ;
		OPT_SR_CLK = 1 ;
		OPT_SR_CLK = 0 ;

		if (order == LSBFIRST)
			value >>= 1 ;
		else
			value <<= 1 ;
	}
}

#endif


void
shiftOut(BYTE data, BYTE clock, BYTE order, BYTE value)
{
	BYTE db, cb, i, v ;
	volatile near unsigned char *dp, *cp ;

	dp = &LATA + GET_PORT(data) - 2 ;
	db = BIT(data & 0b00000111) ;
	cp = &LATA + GET_PORT(clock) - 2 ;
	cb = BIT(clock & 0b00000111) ;

	for (i = 0; i < 8; i++)  {
		v = value & ((order == LSBFIRST) ? 1 : 0b10000000) ;

		/* データピン */
		if (v == 0) {
			(*dp) &= ~db ;
		} else {
			(*dp) |= db ;
		}

		/* クロックピン */
		(*cp) |= cb ;
		(*cp) &= ~cb ;

		if (order == LSBFIRST)
			value >>= 1 ;
		else
			value <<= 1 ;
	}
}
