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

	pic18seg7.c

	Version 1.00: 2009/10/10

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

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

#include "picsys18.h"

#ifdef USE_SEG7

#if defined(PIC_DEV_2550URL)
extern BYTE dataPin, clockPin ;
BYTE segDigit[NDIGIT] ;
#else
static BYTE dataPin, clockPin ;

static BYTE segDigit[NDIGIT_LED] ;
#endif


/* 7セグメントLEDのダイナミック点灯の対象桁 */
static unsigned char gDL = 0 ;
/* 7セグメントLEDの表示データ格納領域 */
static BYTE g7SEG[NDIGIT_LED] ;

/* 7セグメントLEDの表示パターン */
static rom BYTE gPTN[] = {
	0b11111100, /* 0 */
	0b01100000,
	0b11011010,
	0b11110010,
	0b01100110,
	0b10110110,
	0b10111110,
	0b11100000,
	0b11111110,
	0b11100110, /* 9 */

	0b11101110, /* A */
	0b00111110, /* b */
	0b00011010, /* c */
	0b01111010, /* d */
	0b10011110, /* E */
	0b10001110, /* F */
	0b00000000, /*   */
	0b00000010, /* - */
	0b01101110, /* H */
	0b00011100, /* L */
	0b11000110, /* ~ */
	0b00111010, /* _ */
} ;


/***********************************************************
	７セグメントLEDの初期化
***********************************************************/

void
SEG7_init(BYTE dat, BYTE clk, BYTE seg1, BYTE seg2, BYTE seg3, BYTE seg4)
{
	char i ;
	
	dataPin = dat ;
	clockPin = clk ;
	segDigit[0] = seg1 ;
	segDigit[1] = seg2 ;
	segDigit[2] = seg3 ;
	segDigit[3] = seg4 ;
#if defined(PICSYS18_SP)
	segDigit[4] = SEG5 ;
#endif
	pinMode(clockPin, OUTPUT) ;
	pinMode(dataPin, OUTPUT) ;

	shiftOut(dataPin, clockPin, LSBFIRST, 0xff) ;

	for (i = 0; i < NDIGIT_LED; i++) {
	   pinMode(segDigit[i], OUTPUT) ;
	   bitOut(segDigit[i], HIGH) ;
	   g7SEG[i] = 0 ;
    }
    
    _refreshDevice = REFRESH_SEG7 ;
}


#if defined(SR_DAT)

void
SEG7_initDefault()
{
	SEG7_init(SR_DAT, SR_CLK, SEG1, SEG2, SEG3, SEG4) ;
}

#endif


/***********************************************************
	７セグメントLEDへの出力
***********************************************************/

/* 7セグメントLEDへの1桁出力 */
void
SEG7_setDigit(char i, char n)
{
	if (n >= sizeof(gPTN)/sizeof(BYTE)) {
		/* 無効な値の場合には、消灯 */
		g7SEG[(i & 3)] = 0b00000000 ;
	} else {
		/* 数値に対応した点灯パターンの設定 */
		g7SEG[(i & 3)] = gPTN[n] ;

		/* 桁が大きい場合には、ドットを追加表示 */
		if (i >= NDIGIT)
			g7SEG[(i & 3)] |= 0b10000000 ;
	}
}


/* 数値を４桁のデータとして表示 */
void
SEG7_write(int n, BYTE type)
{
	BYTE sign = FALSE ;
	BYTE head = SEG7_BLANK ;
	
	if (n < 0) {
		sign = TRUE ;
		head = SEG7_MINUS ;
		n = -n ;
	}
	
	if (type == SEG7_HEX) {
		SEG7_setDigit(3, n & 0xf) ;
	} else {	
		SEG7_setDigit(3, n % 10) ;
	}

	if (type == SEG7_INT) {
		/* ゼロサプレスで必要であれば先頭にマイナス符号を表示 */
		if (n >= 10) {
			SEG7_setDigit(2, (n / 10) % 10) ;
			if (n >= 100) {
				SEG7_setDigit(1, (n / 100) % 10) ;
				if (n >= 1000) {
					SEG7_setDigit(0, (n / 1000) % 10) ;
				} else {
					SEG7_setDigit(0, head) ;
				}
			} else {
				SEG7_setDigit(1, head) ;
				SEG7_setDigit(0, SEG7_BLANK) ;
			}
		} else {
			SEG7_setDigit(2, head) ;
			SEG7_setDigit(1, SEG7_BLANK) ;
			SEG7_setDigit(0, SEG7_BLANK) ;
		}
	} else if (type == SEG7_HEX) {
		SEG7_setDigit(2, (n >> 4) & 0xf) ;
		SEG7_setDigit(1, (n >> 8) & 0xf) ;
		SEG7_setDigit(0, (n >> 12) & 0xf);
	} else {
		SEG7_setDigit(2, (n / 10) % 10) ;
		SEG7_setDigit(1, (n / 100) % 10) ;
		SEG7_setDigit(0, (n / 1000) % 10 );
	}
}


/* 7セグメントLEDへの1桁出力のセグメントの個別指定 */
void
SEG7_setSegment(char i, BYTE ptn)
{
	g7SEG[(i & 3)] = ptn ;
}


#if defined(PICSYS18_SP)
/***********************************************************
	LEDアレイへの入出力
***********************************************************/

void
LED_write(BYTE n)
{
	g7SEG[NDIGIT] = n ;
}

void
LED_bitWrite(BYTE i, BYTE v)
{
	if (v == 0)
		g7SEG[NDIGIT] &= ~BIT(i) ;
	else
		g7SEG[NDIGIT] |= BIT(i) ;
}

void
LED_bitSet(BYTE i)
{
	g7SEG[NDIGIT] |= BIT(i) ;
}

void
LED_bitClear(BYTE i)
{
	g7SEG[NDIGIT] &= ~BIT(i) ;
}


int
LED_read()
{
	return g7SEG[NDIGIT] ;
}

int
LED_bitGet(BYTE i)
{
	return (g7SEG[NDIGIT] & BIT(i)) ? 1 : 0 ;
}

#endif


/***********************************************************
	ダイナミック表示処理：割り込みサービスルーチンからの呼び出し
***********************************************************/

#ifdef	OPTIMIZE

void
isr_SEG7_update()
{
	char i ;

	/* 今回表示する桁の確認 */
    if (gDL >= NDIGIT_LED)
		gDL = 0 ;

	/* コモン側をすべて非アクティブ化 */
	OPT_SEG1 = 1 ;
	OPT_SEG2 = 1 ;
	OPT_SEG3 = 1 ;
	OPT_SEG4 = 1 ;
#if defined(OPT_SEG5)
	OPT_SEG5 = 1 ;
#endif

#if defined(PIC_DEV_2550URL)
	isr_optShiftOut(LSBFIRST, 0xff) ;

	isr_SW_update() ;
#endif

	/* 1桁分の表示データ(アクティブロウ）の出力 */
	isr_optShiftOut(LSBFIRST, ~g7SEG[gDL]) ;

	/* 該当桁のコモン側をアクティブ化 */
	switch (gDL++) {
		case 0:
			OPT_SEG1 = 0 ;
			break ;
		case 1:
			OPT_SEG2 = 0 ;
			break ;
		case 2:
			OPT_SEG3 = 0 ;
			break ;
		case 3:
			OPT_SEG4 = 0 ;
			break ;
#if defined(OPT_SEG5)
		case 4:
			OPT_SEG5 = 0 ;
			break ;
#endif
	}
}

#else

void
isr_SEG7_update()
{
	char i ;
	
	/* 今回表示する桁の確認 */
    if (gDL >= NDIGIT_LED)
		gDL = 0 ;

	/* コモン側をすべて非アクティブ化 */
    for (i = 0; i < NDIGIT_LED; i++)
		isr_bitOut(segDigit[i], HIGH) ;

#if defined(PIC_DEV_2550URL)
	shiftOut(dataPin, clockPin, LSBFIRST, 0xff) ;

	isr_SW_update() ;
#endif

	/* 1桁分の表示データ(アクティブロウ）の出力 */
	shiftOut(dataPin, clockPin, LSBFIRST, ~g7SEG[gDL]) ;

	/* 該当桁のコモン側をアクティブ化 */
	isr_bitOut(segDigit[gDL++], LOW) ;
}

#endif

#endif
