赤外線リモコンモジュール用プログラム(slave_ir_txrx_18f26k22.c)

// --------------------------------------------------
// Global Versatile Controler http://www.gvc-on.net/
// --------------------------------------------------
// --------------------------------------------------
// Revision Memo (Y.M.D Editor/Memo)
// --------------------------------------------------
//
// 赤外線モジュール用
//
// 赤外線モジュールは大きく別けて以下の二つの動作を行う
// ・既存赤外線リモコン信号の受信(サンプリング)
// ・指定された赤外線リモコン信号の送信
// もともとの赤外線信号をサンプリングしてそれを元にPWMを再生するというおバカ学習リモコンみたいな感じ
// 
// メモリの関係でGVCフォーマットにそった形でメモリ共有する
// 
// ------------------------------
// BASE
// ------------------------------
// 2013.07.10 T.Kabu 測距から赤外線に流用
// 2013.09.06 T.Kabu 送信時に挙動不審になるのは、赤外線LEDでドカン!!と送信しようとしたときの電源ラインの電圧降下が原因らしい
//                   一つは、デカップリングコンデンサ(バイパスコンデンサ)として100uFのMLCCとか電解コンデンサをつけること
//                   で電圧降下をかなり防げるが、赤外線LEDと直列に接続しているRを5Ω程度にしてさらに大電流を流そうとする
//                   と、電圧降下が発生?してPICがリセットする。この原因を探るための仕込みを埋め込む。
// 2013.11.03 T.Kabu エアコンのリモコン信号とGVC空の再送信号をみてみると、どうもGVCからの方が間延びしていて、長い場合5msくらいずれる(3%くらい)
//                   シビアな判定をしている場合には、これだとNGになるのかもしれないので、もう少しきっちりしてみる
//                   ・サンプリングを50usでなく52usとする
//                   ・送信時のON/OFF時間を短くする
// 2013.11.21 T.Kabu 受信時のサンプリングを割り込みでやるのはよいのだが、送信時のバイトをまたぐ(charの配列なりポインタなりで次に行く)だけで
//                   34usとか掛かっちゃうので、そこで38KHzのキャリアが止まる事になってしまう。(1/38kHz=26.3us)
//                   これだときれいではないので、送信も割り込み処理で38kHzを送信しつつON/OFFする事にする。
//                   ということで送信にはTimer3をつかってプリスケーラを1:8から1:4にして送信する
// 2013.11.26 T.Kabu 送信の仕方を、PWMで38KHzを作りつつ、これをSTR1AでON/OFFすることでキャリアのON/OFFとするようにしてみる
// 2013.11.28 T.Kabu 赤外線LEDをサンプリングとは1/0反転させた状態で点灯すると、ばっちり!!
//                   …なので、これでGVCのサンプルモジュールは一通り開発できたので、整理整頓、清書してリリースに向けて前進あるのみ!!
// 2013.12.03 T.Kabu さらにチューニングして、受信/送信時にそれぞれ事前のウェイトとか、1フレームの終わりの検出とかをしっかりしてみた

//---------------------------------------------------
// Include Header
//---------------------------------------------------
// ----------------------------------------
// Standard Header
// ----------------------------------------
#include <xc.h>
#include <plib.h>
#include <htc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// ----------------------------------------
// User Header
// ----------------------------------------
// Pragma Header
#include "pragma.h"

// PIC Parameter define and initialize
#include "pic_init.h"

// GVC Parameter define and initialize
#include "gvc_init.h"

// --------------------------------------------------
// Const Define
// --------------------------------------------------
#define VERSION "=== GVC SLAVE MODULE DEVICE PROGRAM for 18F26K22 (IR) ==="

// PICのI2Cアドレス、適時変更すること
#define	I2C_ADDR			0x10					// モジュールごとにアドレスを変えること!!

// 受信バッファサイズ
#define SERIAL_RCV_BUFFSIZE	16
#define SERIAL_RCV_BUFFRING	15						// SERIAL_RCV_BUFFSIZEから1減らした値を設定

// シリアルバッファサイズ
///#define SERIAL_BUFF_SIZE	3096					// 使わない

// I2Cバッファサイズ
///#define RX_BUFF_SIZE		3096					// 使わない
///#define TX_BUFF_SIZE		3096					// 使わない

#define MAIN_BUFF_SIZE		3096					// この赤外線モジュールのメインバッファサイズ
#define SUB_BUFF_SIZE		256						// この赤外線モジュールのサブバッファサイズ

#define IR_BUFF_SIZE		3000					// MAIN_BUFF_SIZEからGVCのヘッダ情報分だけ引いた値にすること★

// シリアルバッファとI2Cバッファは、それぞれのGVCモジュールで想定しているデータに合わせたサイズにすること
// 赤外線データだけは、どうがんばっても3096バイトをひとつ確保したら終わりなので、それぞれで使い回しをしないといけないので、使い方に注意すること

#define IR_TX_MAX			1						// リモコンデータを再送信する回数

// --------------------------------------------------
// Variable Param
// --------------------------------------------------
// 割り込み処理内でのレジスタの値を格納する変数はここで宣言すること、割り込み処理内で宣言してはいけない!! T.Kabu 2013.05.14
unsigned char reg_RCSTA1;							// 受信ステータスレジスタ
unsigned char reg_SSP1STAT;							// SSP1ステータスレジスタ
unsigned char temp_buffer;							// SSP1BUFの空読み用
GVC_I2C_MESSAGE_t * gvc_i2c_message;				// GVC I2Cメッセージ用ポインタ(tx_buffer/rx_bufferにかぶせる)

unsigned char serial_rcvptr;						// 受信バッファポインタ
unsigned char serial_readptr	;					// 受信読み出しポインタ
unsigned char serial_rcvbuff[SERIAL_RCV_BUFFSIZE];	// 受信リングバッファ(RCREG1)

///unsigned char serial_buffer[SUB_BUFF_SIZE];			// シリアルバッファ(作業用) → sub_bufferにする

///unsigned char rx_buffer[RX_BUFF_SIZE];				// 受信バッファ → とりあえずmain_bufferにする
unsigned int  rx_count = 0;							// 受信バッファ位置

///unsigned char tx_buffer[TX_BUFF_SIZE];				// 送信バッファ → とりあえずsub_bufferにする、でも赤外線データの送信にはmain_bufferでないと
unsigned int  tx_count = 0;							// 送信バッファ位置

unsigned int  i2c_data_len;							// I2Cのデータ長(data_len)

static char   i2c_status = 0;						// I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了

unsigned char ir_mode = 0;							// リモコンモジュール動作モード(0=受信データがあれば再送信、1=読み取り)
unsigned char ir_rxmax = 0;							// リモコン最大受信モード(0=通常、1=最大)

unsigned char main_buffer[MAIN_BUFF_SIZE];			// 赤外線モジュール共通メインバッファ
unsigned char sub_buffer[SUB_BUFF_SIZE];			// 赤外線モジュール共通サブバッファ

//unsigned char ir_buffer[IR_BUFF_SIZE];				// リモコンデータバッファ
unsigned char * ir_buffer;							// リモコンデータバッファポインタ(実エリアでなくてmain_bufferをGVCフォーマットに変換したdata[]部分になる)
unsigned char ir_saved_buffer[8];					// リモコンデータの待避バッファ(他のコマンドで先頭の数バイトが破壊されるから)
unsigned char ir_data;								// リモコンデータ
unsigned char ir_status;							// リモコンデータのひとつ前の状態
unsigned int  ir_count;								// リモコンデータ位置
unsigned char ir_bit;								// リモコンデータビット位置
unsigned char ir_trx_flag;							// リモコン送受信フラグ(0=none, 1=受信中, 2=送信中)
unsigned char ir_rx_status;							// リモコン受信状態(0=none, 1=RXwait,2=RXing etc...)
unsigned int  ir_same_count;						// リモコン同一データカウンタ
unsigned int  ir_data_len;							// リモコンデータ長

unsigned int  timer0_count;							// タイマー0カウンタ
unsigned int  timer1_count;							// タイマー1カウンタ
unsigned char timer0_h;								// タイマー0のHighの値
unsigned char timer0_l;								// タイマー0のLowの値
unsigned char timer1_h;								// タイマー1のHighの値
unsigned char timer1_l;								// タイマー1のLowの値

unsigned char ir_tx_count;							// 赤外線送信回数
unsigned char ir_tx_data;							// 赤外線送信バイト
unsigned char * ir_buffer_end;						// リモコンデータバッファポインタの最後

const char bit_mask_array[8] = {					// ビット計算用の配列(ANDとかですむように)
		0b00000001,
		0b00000010,
		0b00000100,
		0b00001000,
		0b00010000,
		0b00100000,
		0b01000000,
		0b10000000
};

// --------------------------------------------------
// Function prototype
// --------------------------------------------------
// --------------------------------------------------
// Sub Routine
// --------------------------------------------------
// ------------------------------
// Recieve serialdata
// ------------------------------
char rcv_serialdata(void)
{
	unsigned char data;
	
	// 返り値用データに受信データコピー
	data = serial_rcvbuff[serial_readptr];
	// 受信読み出しポインタを加算
	serial_readptr ++;
	// 受信読み出しポインタをリングる
	serial_readptr &= SERIAL_RCV_BUFFRING;
	
	// 受信データを返す
	return data;
}

// ------------------------------
// Send IR RX DATA
// ------------------------------
void send_ir_rxdata(void)
{
	// 送信バッファポインタの終了ポインタを計算(10バイトなら a+10
	ir_buffer_end = ir_buffer + ir_data_len;
	
	// 送信ループ
	do
	{
		// リモコンデータポインタの中身を送信する
		send_hexdata(*ir_buffer);
		
/*** START ***
		// ------------------------------
		// ビット単位で送信する場合にはこんな感じで
		// ------------------------------
		// 各ビットごとに0/1を送信するループ
		for (ir_bit = 0; ir_bit < 8; ir_bit++)
		{
			while(TX1IF == 0);	// 送信可能になるまで待つ
			// リモコンデータの該当ビットが0なら
			if ( (*ir_buffer & bit_mask_array[ir_bit]) == 0 )
			{
				// Hi(=0)のとき
				TXREG1 = 0x30;
			}
			// リモコンデータの該当ビットが1なら
			else
			{
				// Low(=1)のとき
				TXREG1 = 0x31;
			}
		}
*** END ***/
		
		// リモコンデータポインタを加算
		ir_buffer ++;
		
	} while (ir_buffer < ir_buffer_end);	// 終了ポインタまで達していないなら送信ループ
	
	send_crlf();
	
	// このルーチンを抜けるとir_bufferポインタはリモコンデータの最後の次にすっ飛んでいるので再設定忘れずに
}

// ----------------------------------------
// Setup 18F26K22 for Analog Voltage
// ----------------------------------------
void init_pic_for_analogvoltage(void)
{
	// ------------------------------
	// ポートA設定
	// ------------------------------
	// bit7   : RA7 1 = input, 0 = output
	// bit6   : RA6 1 = input, 0 = output
	// bit5   : RA5 1 = input, 0 = output
	// bit4   : RA4 1 = input, 0 = output
	// bit3   : RA3 1 = input, 0 = output
	// bit2   : RA2 1 = input, 0 = output
	// bit1   : RA1 1 = input, 0 = output
	// bit0   : RA0 1 = input, 0 = output
	TRISA = 0b00001111;		// RA0-RA3をを電圧測定用にinputモード
	
	// ANSELA: PORTA ANALOG SELECT REGISTER ポートのI/Oモードの設定。
	// bit7-6 : none (0)
	// bit5   : ANSA4: Analog Select between Analog or Digital Function on pins RA5, respectively
	//            0 = Digital I/O. Pin is assigned to port or digital special function.
	//            1 = Analog input. Pin is assigned as analog input(1). Digital input buffer disabled.
	// bit4   : none (0)
	// bit3   : ANSA3: Analog Select between Analog or Digital Function on pins RA3, respectively
	// bit2   : ANSA2: Analog Select between Analog or Digital Function on pins RA2, respectively
	// bit1   : ANSA1: Analog Select between Analog or Digital Function on pins RA1, respectively
	// bit0   : ANSA0: Analog Select between Analog or Digital Function on pins RA0, respectively
	ANSELA = 0b00001111;	// AN0(=RA0),AN1(=RA1),AN2(=RA2),AN3(=RA3) Analog input
	
	// ADCON0 は、実際に電圧を読むときに、そのポートを指定しないといけないのでここではいじらない
	
	// bit 7 TRIGSEL: Special Trigger Select bit
	//     1 = Selects the special trigger from CTMU
	//     0 = Selects the special trigger from CCP5
	// bit 6-4 Unimplemented: Read as ‘0’
	// bit 3-2 PVCFG<1:0>: Positive Voltage Reference Configuration bits
	//     00 = A/D VREF+ connected to internal signal, AVDD
	//     01 = A/D VREF+ connected to external pin, VREF+
	//     10 = A/D VREF+ connected to internal signal, FVR BUF2
	//     11 = Reserved (by default, A/D VREF+ connected to internal signal, AVDD)
	// bit 1-0 NVCFG0<1:0>: Negative Voltage Reference Configuration bits
	//     00 = A/D VREF- connected to internal signal, AVSS
	//     01 = A/D VREF- connected to external pin, VREF-
	//     10 = Reserved (by default, A/D VREF+ connected to internal signal, AVSS)
	//     11 = Reserved (by default, A/D VREF+ connected to internal signal, AVSS)
///	ADCON1 = 0b00000000;		// VREF+、VREF-ともに内部供給電圧Vddに対しての値となる
	ADCON1 = 0b00001000;		// VREF+はFVRから、VREF-はGNDに対しての値となる
	
	// AD変換制御レジスタ2設定 A/D CONTROL REGISTER 2
	// bit 7 ADFM: A/D Conversion Result Format Select bit
	//     1 = Right justified
	//     0 = Left justified
	// bit 6 Unimplemented: Read as ‘0’
	// bit 5-3 ACQT<2:0>: A/D Acquisition time select bits. Acquisition time is the duration that the A/D charge holding
	//         capacitor remains connected to A/D channel from the instant the GO/DONE bit is set until conversions
	//         begins.
	//     000 = 0(1)
	//     001 = 2 TAD
	//     010 = 4 TAD
	//     011 = 6 TAD
	//     100 = 8 TAD
	//     101 = 12 TAD
	//     110 = 16 TAD
	//     111 = 20 TAD
	// bit 2-0 ADCS<2:0>: A/D Conversion Clock Select bits
	//     000 = FOSC/2
	//     001 = FOSC/8
	//     010 = FOSC/32
	//     011 = FRC(1) (clock derived from a dedicated internal oscillator = 600 kHz nominal)
	//     100 = FOSC/4
	//     101 = FOSC/16
	//     110 = FOSC/64
	//     111 = FRC(1) (clock derived from a dedicated internal oscillator = 600 kHz nominal)
	ADCON2 = 0b10110101;	// 右寄せ、16TAD、FOSC/16
	
	// 電圧リファレンス制御レジスタ0 FIXED VOLTAGE REFERENCE CONTROL REGISTER
	// bit 7 FVREN: Fixed Voltage Reference Enable bit
	//     0 = Fixed Voltage Reference is disabled
	//     1 = Fixed Voltage Reference is enabled
	// bit 6 FVRST: Fixed Voltage Reference Ready Flag bit
	//     0 = Fixed Voltage Reference output is not ready or not enabled
	//     1 = Fixed Voltage Reference output is ready for use
	// bit 5-4 FVRS<1:0>: Fixed Voltage Reference Selection bits
	//     00 = Fixed Voltage Reference Peripheral output is off
	//     01 = Fixed Voltage Reference Peripheral output is 1x (1.024V)
	//     10 = Fixed Voltage Reference Peripheral output is 2x (2.048V)(1)
	//     11 = Fixed Voltage Reference Peripheral output is 4x (4.096V)(1)
	// bit 3-2 Reserved: Read as ‘0’. Maintain these bits clear.
	// bit 1-0 Unimplemented: Read as ‘0’.
	VREFCON0 = 0b10110000;	// FVR有効、x4の4.096Vとする
}

// ------------------------------
// Setup MSSP1 18F26K22
// ------------------------------
void init_mssp1_18F26K22(void)
{
	// ------------------------------
	// MSSP1制御データ設定 スレーブとして設定する場合
	// ------------------------------
	// bit 7   : SMP 1 = Slew rate control disabled for standard speed mode (100 kHz and 1 MHz)
	//         :     0 = Slew rate control enabled for high speed mode (400 kHz)
	// bit 6   : CKE 1 = Enable input logic so that thresholds are compliant with SMbus specification
	//         :     0 = Disable SMbus specific inputs
	// bit 5   : D/A: Data/Address bit (I2C mode only)
	//         :     1 = Indicates that the last byte received or transmitted was data
	//         :     0 = Indicates that the last byte received or transmitted was address
	// bit 4   : P: Stop bit
	//         : (I2C mode only. This bit is cleared when the MSSPx module is disabled, SSPxEN is cleared.)
	//         :     1 = Indicates that a Stop bit has been detected last (this bit is ‘0’ on Reset)
	//         :     0 = Stop bit was not detected last
	// bit 3   : S: Start bit
	//         : (I2C mode only. This bit is cleared when the MSSPx module is disabled, SSPxEN is cleared.)
	//         :     1 = Indicates that a Start bit has been detected last (this bit is ‘0’ on Reset)
	//         :     0 = Start bit was not detected last
	// bit 2   : R/W: Read/Write bit information (I2C mode only)
	//         : In I2 C Master mode:
	//         :     1 = Transmit is in progress
	//         :     0 = Transmit is not in progress
	//         : OR-ing this bit with SEN, RSEN, PEN, RCEN or ACKEN will indicate if the MSSPx is in Idle mode.
	//         : (このビットと、SEN、RSEN、PEN、RCEN、またはACKEN との論理和を取ると、マスタモードがアクティブかどうかを判断できる)
	// bit 1   : UA: Update Address bit (10-bit I2C mode only)
	// bit 0   : BF: Buffer Full Status bit
	//         : Receive (SPI and I2 C modes):
	//         :     1 = Receive complete, SSPxBUF is full
	//         :     0 = Receive not complete, SSPxBUF is empty
	//         : Transmit (I2 C mode only):
	//         :     1 = Data transmit in progress (does not include the ACK and Stop bits), SSPxBUF is full
	//         :     0 = Data transmit complete (does not include the ACK and Stop bits), SSPxBUF is empty
	SSP1STAT = 0b00000000;	// 400kHz Slew rate
	
	// bit7   : WCOL master(1 = Collision, 0 = No Collision), slave(1 = must be cleard, 0 = No Collision)
	// bit6   : SSP1OV SPI(pass), I2C(1 = overflow, 0 = not Overflow)
	// bit5   : SSP1EN SPI(pass), I2C(1 = enable SDA/SCL w/input mode, 0 = disable)
	// bit4   : CKP    SPI(pass), I2C(master(1 = enable clock, 0 = hold clock low), slave (unused))
	// bit3-0 : SSP1M  0110 I2C Slave mode, 7bit address
	//        : SSP1M  0111 I2C Slave mode, 10bit address
	//        : SSP1M  1000 I2C Master mode, clock = Fosc/(4 * (SSP1ADD + 1))
	//        : SSP1M  1011 I2C F/W controled Master mode(Slave Idle)
	//        : SSP1M  1110 I2C Slave mode, 7bit address w/Start/Stop bit INT
	//        : SSP1M  1111 I2C Slave mode, 10bit address w/Start/Stop bit INT
	SSP1CON1 = 0b00110110;		// SSP1EN = 1, CKP = 1, SSP1M = Slave mode 7bit 
	
	SSP1CON2bits.SEN = 1;		// Start Condition Enabled bit ... SSP1CON2) ←マスターからデータを受け取るなら設定必要
	
	// このデバイスのI2Cアドレスを設定
	SSP1ADD = I2C_ADDR << 1;
	
	// MSSP1割り込み初期化
	PIR1bits.SSP1IF = 0;
	
	// MSSP1バス衝突割り込みフラグを初期化
	PIR2bits.BCL1IF = 0;
	
	// 100ms待つ
	Delay_10ms(10);
}

// ------------------------------
// Setup Timer 18F26K22
// ------------------------------
void init_timer_18F26K22(void)
{
	// 割り込み処理内でビットシフトとかあれかな?と思ってここで予め作っておくことにする
	
	// 受信タイムアウトタイマー値設定
	timer0_h = (TIMER_100ms >> 8);
	timer0_l = (TIMER_100ms & 0x00ff);
	
	// 受信サンプリング用タイマー値設定
	timer1_h = (TIMER_80us >> 8);
	timer1_l = (TIMER_80us & 0x00ff);
	
}

// ------------------------------
// Interrupt Routine
// ------------------------------
// I2Cのマスターとスレーブとのやり取りは、データシートの説明が言葉足らずなために
// 非常に判りづらい。ただし、判ってしまうと何だそれだけか、となる。
// 
// 特にスレーブ側であれこれ設定したり判定や処理に必要なのは次のビット
// ・D/A…1=SSP1BUFの中はデータ、0=SSP1BUFの中はアドレス(空っぽ…空の読み出し要求時)
// ・R/W…1=マスターがスレーブから受信、0=マスターがスレーブへ送信
// ・BF…1=バッファに何か入っている(空の読み出し要求時も)、0=バッファは空っぽ
// ・CKP…マスターにデータ送信を許可するとき、スレーブから送信するときに1にしてSCLをリリースする
// ・SSP1IF…割り込みフラグ、なんかしたらクリアする
// ・SEN…マスターからデータを受信する時に、ソフト側でCKPを制御するために1にする。0だとうまく動かないよ!!
//(・S…スタートビット、特に使わなくてもいい気がする)
//
// で、判定に使うビットが多いけど、基本的にはSSP1STATなので、マスクして一括判定すればOK。
// 
// 赤外線リモコンデータの送信では、送信用の割り込みが来たらとりあえずすぐに出力を変更してから、次のデータの
// 設定などをする。次の割り込みまでは80usしかない(サンプリング間隔を短くしたらもっと少ない)ので、処理は極力
// 単純にして短時間で済ますようにすること
// 
// --------------------------------------------------
// 18F26K22 Interrupt Routine
// --------------------------------------------------
// 割り込みはすべてinterrupt宣言されたこの関数が呼ばれる
static void interrupt interrupt_18F26K22()
{
	// 全割り込みを禁止(=0) (Global Interrupt Enable bit ... INTCON)
	INTCONbits.GIE = 0;
	
	// ----------------------------------------
	// リモコン読み取りサンプリングタイマー or 送信用タイマー
	// ----------------------------------------
	// タイマー1割り込み(=1)なら (Timer1 Overflow Interrupt Flag bit ... PIR1)
	if (PIR1bits.TMR1IF == 1)
	{
		// タイマー1カウンタを加算
		timer1_count ++;
		
		// タイマー値設定
		TMR1H = timer1_h;
		TMR1L = timer1_l;
		// タイマー割り込みフラグ初期化
		PIR1bits.TMR1IF = 0;
		
		// サンプリングタイマーカウンタが1回になったら
		if (timer1_count >= 1)
		{
			// ----------------------------------------
			// もしリモコン送受信フラグが受信中なら
			// ----------------------------------------
			if (ir_trx_flag == 1)
			{
				// リモコンデータを取得
				ir_data = PORT_IR_RX;
				
				// リモコン受信状態が受信待ち(1)なら
				if (ir_rx_status == 1)
				{
					// リザルトLEDとir_dataが同じでないなら
					if (ir_data != ir_status)
					{
						// リモコン受信状態を受信中(2)に設定
						ir_rx_status = 2;
					}
				}	
				// リモコン受信状態が受信中なら
				if (ir_rx_status == 2)
				{
					// リモコンデータが1なら
					if (ir_data == 1)
					{
						// リモコンデータビット位置に1を立てて(足し算でOK)、ビットマスク結果に設定
						*ir_buffer += ir_bit;
					}
					
					// リモコンデータビット位置を左シフト(つまり+1)
					ir_bit <<= 1;
					ir_bit &= 0xff;
					
					// リモコンデータビット位置がオーバーフローしたら
					if (ir_bit == 0)
					{
						// リモコンデータビット位置をクリア
						ir_bit = 1;
						// リモコンデータポインタを加算
						ir_buffer ++;
						// リモコンデータ位置を+1
						ir_count ++;
					}
					
					// リモコンデータ位置がIR_BUFF_SIZEになったら ★実際の格納位置に注意
					if (ir_count == IR_BUFF_SIZE)
					{
						// リモコンデータ長を設定
						ir_data_len = ir_count;
						// リモコン受信状態をエラー(-99:バッファオーバーフロー)に
						ir_rx_status = -99;
						// リザルトLEDを消灯
						PORT_RESULT_LED = LED_OFF;
						// ステータスLEDを消灯
						PORT_STATUS_LED = LED_OFF;
						// リモコン最大受信モードが通常(=0)なら
						if (ir_rxmax == 0)
						{
							// ★割り込み処理を抜けて、別途エラー処理
							return;
						}
						// リモコン最大受信モードが最大(=1)なら
						else if (ir_rxmax == 1)
						{
							// リモコン受信状態を受信完了(99)に
							ir_rx_status = 99;
							// メインバッファをI2Cメッセージポインタに設定
							gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
							// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
							ir_buffer = gvc_i2c_message->data;
							// 待避バッファに赤外線データをコピー
							ir_saved_buffer[1] = ir_buffer[1];
							ir_saved_buffer[2] = ir_buffer[2];
							ir_saved_buffer[3] = ir_buffer[3];
							ir_saved_buffer[4] = ir_buffer[4];
							ir_saved_buffer[5] = ir_buffer[5];
							ir_saved_buffer[6] = ir_buffer[6];
							ir_saved_buffer[7] = ir_buffer[7];
						}
					}
					
					// リモコンデータが同じであり、リモコン最大受信モードが通常(=0)なら
					if ((ir_data == ir_status) && (ir_rxmax == 0))
					{
						// リモコン同一データカウンタ++
						ir_same_count ++;
						// リモコン同一データカウンタが10ms(50usの場合には200、80usの場合には125)続いたら ←ソニーフォーマットでいまいち
						// リモコン同一データカウンタが20ms(50usの場合には400、80usの場合には250)続いたら
						// リモコン同一データカウンタが30ms(50usの場合には600、80usの場合には375)続いたら ←同一信号の再送信にかかることがある
						// …どうもうちのリモコンはいっぱい送っているのでは?と思って、終了判定を長めにしてみた。
						// これでもダメなら、やはりストレージオシロか何かでリモコン波形を見ながら出ないとね。2013.07.31 T.Kabu
						if (ir_same_count > 250)
						{
							// リモコンデータ長を設定
							ir_data_len = ir_count;
							// リモコン受信状態を受信完了(99)に
							ir_rx_status = 99;
							// メインバッファをI2Cメッセージポインタに設定
							gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
							// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
							ir_buffer = gvc_i2c_message->data;
							// 待避バッファに赤外線データをコピー
							ir_saved_buffer[1] = ir_buffer[1];
							ir_saved_buffer[2] = ir_buffer[2];
							ir_saved_buffer[3] = ir_buffer[3];
							ir_saved_buffer[4] = ir_buffer[4];
							ir_saved_buffer[5] = ir_buffer[5];
							ir_saved_buffer[6] = ir_buffer[6];
							ir_saved_buffer[7] = ir_buffer[7];
							// LEDを点灯しっぱなしに
							PORT_RESULT_LED = LED_ON;
						}
					}
					// そうではないなら
					else
					{
						// リモコン同一データカウンタをリセット
						ir_same_count = 0;
					}
				}
				// リモコン受信状態が受信中なら
				if (ir_rx_status == 2)
				{
					// リモコンデータを次との比較のために設定
					ir_status = ir_data;
				}
				// タイマー1カウンターリセット
				timer1_count = 0;
			}
			// ----------------------------------------
			// もしリモコン送受信フラグが送信中なら
			// ----------------------------------------
			if (ir_trx_flag == 2)
			{
				// 赤外線LEDの点灯は、サンプリングデータと1/0反転させること!!
				// リモコン送信ビットに基づいてPSTR1CONを設定
				// 送信データが0なら
				if (ir_tx_data == 0)
				{
					// PSTR1CON を設定(送信)
					PSTR1CON = 0b00010001;	// STR1SYNC = 1, STR1A = 1;
				}
				// 送信データが1なら
				else
				{
					// PSTR1CON を設定(停止)
					PSTR1CON = 0b00010000;	// STR1SYNC = 1, STR1A = 0;
				}
				
				// リモコンデータビット位置を左シフト(つまり+1)
				ir_bit <<= 1;
				ir_bit &= 0xff;
				
				// リモコンデータビット位置がオーバーフローしたら
				if (ir_bit == 0)
				{
					// リモコンデータビット位置をクリア
					ir_bit = 1;
					// リモコンデータポインタを加算
					ir_buffer ++;
					// リモコンデータ位置を+1
					ir_count ++;
				}
				// 次のリモコンデータの送信ビットを設定(送信バイトと送信対象ビットをANDした値)
				ir_tx_data = *ir_buffer & ir_bit;
				
				// リモコン送信データの最後まで行ったら
				if (ir_buffer == ir_buffer_end)
				{
					// 赤外線送信回数を加算
					ir_tx_count ++;
					
					// 赤外線送信回数が規定値を超えたら
					if (ir_tx_count > IR_TX_MAX)
					{
						// ------------------------------
						// リモコンデータ送信タイマー停止
						// ------------------------------
						T1CON &= 0b11111110;
						// ------------------------------
						// リモコンデータ送信用PWM停止
						// ------------------------------
						// PWM用タイマー(TIMER2)を停止(詳しくはデータシート参照)
						T2CON &= 0b11111011;
						// PSTR1CON を設定(停止)
						PSTR1CON = 0b00000000;	// STR1SYNC = 1, STR1A = 0;
						// リモコン送受信フラグを送受信無し(=0)に設定
						ir_trx_flag = 0;
						// 送信開始LED消灯
						PORT_RESULT_LED = LED_OFF;
					}
					// まだ送信しなければならないなら
					else
					{
						// メインバッファをI2Cメッセージポインタに設定
						gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
						// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
						ir_buffer = gvc_i2c_message->data;
						
						// リモコンデータ位置の初期化
						ir_count = 0;
						// リモコンデータビット位置の初期化
						ir_bit = 1;
						// 初回の送信ビットを設定(送信バイトと送信対象ビットをANDした値)
						ir_tx_data = *ir_buffer & ir_bit;
					}
				}
				// タイマー1カウンターリセット
				timer1_count = 0;
			}
		}
	}
	
	// ----------------------------------------
	// 100ms間隔タイマー
	// ----------------------------------------
	// タイマー0割り込み(=1)なら (Timer0 Overflow Interrupt Flag bit ... INTCON)
	if (INTCONbits.TMR0IF == 1)
	{
		// タイマー0カウンタを加算
		timer0_count ++;
		
		// タイマー値設定
		TMR0H = timer0_h;
		TMR0L = timer0_l;
		// タイマー割り込みフラグ初期化
		INTCONbits.TMR0IF = 0;
		
		// もしカウンタが50回(=5s)になったら
		if (timer0_count >= 50)
		{
			// リモコン送受信フラグが受信中(=1)なら→受信終了
			if (ir_trx_flag == 1)
			{
				// ------------------------------
				// リモコン読み取りタイムアウトタイマー停止
				// ------------------------------
				T0CON &= 0b01111111;
				// ステータスLEDをOFF
				PORT_STATUS_LED = LED_OFF;
				
				// ------------------------------
				// リモコンデータ受信サンプリングタイマー停止
				// ------------------------------
				T1CON &= 0b11111110;
				// サンプリングタイマーのリザルトLEDもOFFに
				PORT_RESULT_LED = LED_OFF;
				
				// タイマー0カウンターリセット
				timer0_count = 0;
				
				// リモコン受信状態を受信完了(99)に
				ir_rx_status = 99;
				
				// リモコン送受信フラグを送受信無し(=0)に設定
				ir_trx_flag = 0;
			}
		}
	}
	
	// ----------------------------------------
	// MSSP1割り込み処理 (Rev.1の18F26K22_I2C.cを参照すること
	// ----------------------------------------
	// MSSP割り込み(=1)なら (Synchronous Serial Port (MSSP) Interrupt Flag bit ... PIR1)
	if (PIR1bits.SSP1IF == 1)
	{
		// ステータスLEDを点灯
		PORT_STATUS_LED = LED_ON;
		
		// MSSP割り込みクリア(=0) (Synchronous Serial Port (MSSP) Interrupt Flag bit ... PIR1)
		PIR1bits.SSP1IF = 0;
		
		// SSP1ステータスを取得、D/A、R/W、BFビットをマスク
		reg_SSP1STAT = SSP1STAT & 0b00100101;
		
		// SSP1ステータスが、アドレス(D/A=0)で、かつマスターがスレーブへ送信(R/W=0)、かつバッファに何かある(BF=1)なら
		if (reg_SSP1STAT == 0b00000001)
		{
			// リザルトLEDを点灯
			PORT_RESULT_LED = LED_ON;
			
			// SSP1BUFを空読みして
			temp_buffer = SSP1BUF;
			// 受信バッファ位置を初期化
			rx_count = 0;
			
			// I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了
			i2c_status = 1;
			
			// SCLをリリースしてマスターにデータの送信を許可する
			SSP1CON1bits.CKP1 = 1;
			
			// リザルトLEDを消灯
			PORT_RESULT_LED = LED_OFF;
		}
		// SSP1ステータスが、データ(D/A=1)で、かつマスターがスレーブへ送信(R/W=0)、かつバッファに何かある(BF=1)なら
		else if (reg_SSP1STAT == 0b00100001)
		{
			// リザルトLEDを点灯
			PORT_RESULT_LED = LED_ON;
			
			// SSP1BUFからデータを読み出して、受信バッファの受信バッファ位置に設定
			main_buffer[rx_count] = SSP1BUF;
			
			// 受信バッファ位置が3まで来てたら
			if (rx_count == 3)
			{
				// このあと受信するデータ長を設定
				i2c_data_len = *(int *)(main_buffer + 2);
			}
			// 受信バッファ位置がchecksum(つまりメッセージ終了)なら
			if (rx_count == (GVC_I2C_MESSAGE_HEADER_SIZE + i2c_data_len))
			{
				// --------------------------------------------------------------------------------
				// 必要ならメッセージ受信したよフラグでも立ててメインループ内で処理してもらう
				// --------------------------------------------------------------------------------
				// I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了
				i2c_status = 10;
				
				// 
				// ・メッセージデータのCRCを検査
				// ・OKならフォーマットやコマンドに基づいて処理、NGならシリアルにその旨出力
				// 
				// CRCチェックがOKなら
				if (GetCRC8((void *)main_buffer, rx_count + 1) == 0)
				{
					// サブバッファをI2Cメッセージポインタに設定
					gvc_i2c_message = (GVC_I2C_MESSAGE_t *)sub_buffer;
					gvc_i2c_message->format = main_buffer[0];		// マスターからの要求フォーマットをそのまま返す
					gvc_i2c_message->cmd = main_buffer[1];		// エラーの場合にはここを違うデータにするのがいいと思う…TBD
					// 要求コマンドが0x91なら
					if (main_buffer[1] == 0x91)
					{
						// リモコンデータ送信要求
						sprintf(gvc_i2c_message->data, "IR TX");
						gvc_i2c_message->data_len = strlen(gvc_i2c_message->data);		// データ長
						// リモコンモードを再送信モード(=2)に設定
						ir_mode = 2;
					}
					// 要求コマンドが0x92なら
					else if (main_buffer[1] == 0x92)
					{
						// リモコンデータ受信要求
						sprintf(gvc_i2c_message->data, "IR RX");
						gvc_i2c_message->data_len = strlen(gvc_i2c_message->data);		// データ長
						// リモコンモードを読み取りモード(=1)に設定
						ir_mode = 1;
					}
					// 要求コマンドが0x93なら
					else if (main_buffer[1] == 0x93)
					{
						send_strdata("--- IR SET REQUEST ---");
						send_crlf();
						
						// メインバッファをI2Cメッセージポインタに設定
						gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
						// リモコン受信状態を受信完了(99)にする
						ir_rx_status = 99;
						// 赤外線データのデータ長を設定する
						ir_data_len = gvc_i2c_message->data_len;
						// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
						ir_buffer = gvc_i2c_message->data;
						// 待避バッファに赤外線データをコピー
						ir_saved_buffer[0] = ir_buffer[0];
						ir_saved_buffer[1] = ir_buffer[1];
						ir_saved_buffer[2] = ir_buffer[2];
						ir_saved_buffer[3] = ir_buffer[3];
						ir_saved_buffer[4] = ir_buffer[4];
						ir_saved_buffer[5] = ir_buffer[5];
						ir_saved_buffer[6] = ir_buffer[6];
						ir_saved_buffer[7] = ir_buffer[7];
						
						// サブバッファをI2Cメッセージポインタに設定
						gvc_i2c_message = (GVC_I2C_MESSAGE_t *)sub_buffer;
						// リモコンデータ設定要求
						sprintf(gvc_i2c_message->data, "IR SET, ir_data_len=%d", ir_data_len);
						gvc_i2c_message->data_len = strlen(gvc_i2c_message->data);		// データ長
						
						send_strdata("DATA LENGTH = ");
						send_intdata(ir_data_len);
						send_crlf();
						send_strdata("STATUS = ");
						send_intdata(ir_rx_status);
						send_crlf();
						send_strdata("--- IR SET END ---");
						send_crlf();
					}
					// 要求コマンドが0x94なら
					else if (main_buffer[1] == 0x94)
					{
						send_strdata("--- IR GET REQUEST ---");
						send_crlf();
						send_strdata("DATA LENGTH = ");
						send_intdata(ir_data_len);
						send_crlf();
						send_strdata("STATUS = ");
						send_intdata(ir_rx_status);
						send_crlf();
						
						// リモコン受信状態が受信完了(99)なら
						if (ir_rx_status == 99)
						{
							// リモコンデータを扱うときには、メッセージポインタをmain_bufferに切り替えないといけない
							// メインバッファをI2Cメッセージポインタに設定
							gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
							// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
							ir_buffer = gvc_i2c_message->data;
							// 待避バッファから赤外線データをコピー
							ir_buffer[0] = ir_saved_buffer[0];
							ir_buffer[1] = ir_saved_buffer[1];
							ir_buffer[2] = ir_saved_buffer[2];
							ir_buffer[3] = ir_saved_buffer[3];
							ir_buffer[4] = ir_saved_buffer[4];
							ir_buffer[5] = ir_saved_buffer[5];
							ir_buffer[6] = ir_saved_buffer[6];
							ir_buffer[7] = ir_saved_buffer[7];
							// フォーマットをバイナリデータとして設定
							gvc_i2c_message->format = 0x31;				// データフォーマット
							gvc_i2c_message->cmd = main_buffer[1];		// エラーの場合にはここを違うデータにするのがいいと思う…TBD
							// データ長を設定
							gvc_i2c_message->data_len = ir_data_len;		// データ長
						}
						// それ以外なら
						else
						{
							// 正常なデータはありません、とするべき
							// リモコンデータが無い旨を返す、formatも正常系と別けること
							sprintf(gvc_i2c_message->data, "IR DATA NONE!? ir_rx_status=%d, ir_data_len=%d, ir_mode=%d, ir_trx_flag=%d", ir_rx_status, ir_data_len, ir_mode, ir_trx_flag);
							gvc_i2c_message->data_len = strlen(gvc_i2c_message->data);		// データ長
						}
						
						send_strdata("--- IR GET END ---");
						send_crlf();
					}
					// 要求コマンドが0x95なら
					else if (main_buffer[1] == 0x95)
					{
						// リモコンデータメモリ削除要求
						sprintf(gvc_i2c_message->data, "IR DEL");
						gvc_i2c_message->data_len = strlen(gvc_i2c_message->data);		// データ長
						// リモコンモードをデータ削除モード(=5)に設定
						ir_mode = 5;
					}
					else
					{
						// コマンドエラーを設定
						sprintf(gvc_i2c_message->data, "Unsupported %02x", temp_buffer);
						gvc_i2c_message->data_len = strlen(gvc_i2c_message->data);		// データ長
					}
					// CRCを計算して、メッセージの最後に設定
					gvc_i2c_message->data[gvc_i2c_message->data_len] = GetCRC8((void *)gvc_i2c_message, GVC_I2C_MESSAGE_HEADER_SIZE + gvc_i2c_message->data_len);
				}
				// CRCチェックがNGなら
				else
				{
					sprintf(sub_buffer, "MASTER MESSAGE CRC ERROR!?");
				}
			}
			// 受信バッファ位置を+1
			rx_count ++;
			// SCLをリリースしてマスターにデータの送信を許可する
			SSP1CON1bits.CKP1 = 1;
			// 受信データがバッファいっぱいになったりしたらフラグでも立ててエラー処理とかする ★実際の格納位置に注意
			if (rx_count >= MAIN_BUFF_SIZE)
			{
				// リザルトLEDを消灯
				PORT_RESULT_LED = LED_ON;
				rx_count = 0;
			}
			// それ以外なら正常ということで
			else
			{
				// リザルトLEDを消灯
				PORT_RESULT_LED = LED_OFF;
			}
		}
		// アドレス(D/A=0)で、かつマスターがスレーブから受信(R/W=1)、かつバッファに何かある(BF=1)な
		else if (reg_SSP1STAT == 0b00000101)
		{
			// リザルトLEDを点灯
			PORT_RESULT_LED = LED_ON;
			
			// SSP1BUFを空読みして
			temp_buffer = SSP1BUF;
			// 送信バッファ位置を初期化
			tx_count = 0;
			// 送信バッファの最初のデータをSSP1BUFに設定
			SSP1BUF = *((char *)(gvc_i2c_message) + tx_count);
			// SCLをリリースしてマスターにデータの送信を許可する
			SSP1CON1bits.CKP1 = 1;
			// 送信バッファ位置を+1;
			tx_count ++;
			
			// リザルトLEDを消灯
			PORT_RESULT_LED = LED_OFF;
		}
		// データ(D/A=1)で、かつマスターがスレーブから受信(R/W=1)、かつバッファが空(BF=0)なら
		else if (reg_SSP1STAT == 0b00100100)
		{
			// リザルトLEDを点灯
			PORT_RESULT_LED = LED_ON;
			
			// 送信バッファ位置がGVC_I2C_MESSAGE_HEADER_SIZE+データサイズ+CRCを越えていないなら
			if (tx_count < (GVC_I2C_MESSAGE_HEADER_SIZE + gvc_i2c_message->data_len + 1))
			{
				// 送信バッファの送信バッファ位置のデータをSSP1BUFに設定
				SSP1BUF = *((char *)(gvc_i2c_message) + tx_count);
				// SCLをリリースしてマスターにデータの送信を許可する
				SSP1CON1bits.CKP1 = 1;
				// 送信バッファ位置を+1;
				tx_count ++;
			}
			// そうではなく、送信バッファ位置がGVC_I2C_MESSAGE_HEADER_SIZE+データサイズを超えていたら…変なデータを返さないようにする
			else
			{
				// ダミーデータ(NULLデータ)を設定する
				SSP1BUF = 0x00;
				// SCLをリリースしてマスターにデータの送信を許可する
				SSP1CON1bits.CKP1 = 1;
			}
			
			// リザルトLEDを消灯
			PORT_RESULT_LED = LED_OFF;
		}
		// これら以外は
		else
		{
			// SSP1BUFを空読みして
			temp_buffer = SSP1BUF;
			// SCLをリリースしてマスターに次の命令を促す
			SSP1CON1bits.CKP1 = 1;
		}
		
		PORT_STATUS_LED = LED_OFF;
	}
	
	// ----------------------------------------
	// シリアル1受信割り込み処理
	// ----------------------------------------
	// シリアル1受信割り込み(=1)なら (RC1IF: EUSART1 Receive Interrupt Flag bit ... INTCON)
	// 1 = The EUSART1 receive buffer, RCREG1, is full (cleared when RCREG1 is read)
	// 0 = The EUSART1 receive buffer is empty
	if (PIR1bits.RC1IF == 1)
	{
		// シリアル1受信割り込みクリア(=0)…は1バイト受信すれば自動的にクリアされるので必要ない ← うそ、要るみたい、時々ちゃんと初期化しない 2013.12.03 
		PIR1bits.RC1IF = 0;
		// 受信ステータスを取得
		reg_RCSTA1 = RCSTA1;
		// 受信ステータスを確認してフレーミングエラー、オーバーランエラーがなければ
		if ((reg_RCSTA1 & 0b00000110) == 0b00000000)
		{
			// 受信バッファ(RCREG1)から1バイト取得
			serial_rcvbuff[serial_rcvptr] = RCREG1;
			// 受信バッファポインタを加算(+1)
			serial_rcvptr ++;
			// 受信バッファポインタをリングる
			serial_rcvptr &= SERIAL_RCV_BUFFRING;
		}
		// 受信ステータスを確認してオーバーランエラーがあるなら
		else if (reg_RCSTA1 & 0b00000010)
		{
			// CREN レシーバイネーブルビットをクリアして再設定
			RCSTA1bits.CREN = 0;
			RCSTA1bits.CREN = 1;
		}
		// エラーがないなら
		else
		{
			// 受信バッファ(RCREG1)から1バイト取得
			serial_rcvbuff[serial_rcvptr] = RCREG1;
		}
		
		// ほんとはここで、受信バッファポインタserial_rcvptrがリングバッファを上書きしないように
		// するとか、あわせてフロー制御するとか、いろいろあるけど、今回はとりあえずほっとく
	}
	
	
	// 全割り込みを許可(=1) (Global Interrupt Enable bit ... INTCON)
	INTCONbits.GIE = 1;
}

// ------------------------------
// IR JOB RX
// ------------------------------
void ir_job_rx(void)
{
	// 数秒置いてから受信処理を開始する
	Delay_10ms(100);    // 1000ms待つ
	Delay_10ms(100);    // 1000ms待つ
	Delay_10ms(100);    // 1000ms待つ
	
	// リモコンデータを扱うときには、メッセージポインタをmain_bufferに切り替えないといけない
	// メインバッファをI2Cメッセージポインタに設定
	gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
	// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
	ir_buffer = gvc_i2c_message->data;
	
	// リモコンデータバッファのクリア
	memset((void *)ir_buffer, 0, IR_BUFF_SIZE);
	// リモコンデータ位置の初期化
	ir_count = 0;
	// リモコンデータビット位置の初期化
	ir_bit = 1;
	// リモコン受信状態を受信待ち(1)に設定
	ir_rx_status = 1;
	// リモコン同一データカウンタを初期化
	ir_same_count = 0;
	// リモコンデータ長を初期化
	ir_data_len = 0;
	
	// 受信開始を送信
	send_strdata("--- IR RX START ---");
	send_crlf();
	
	// 受信動作フラグを受信開始に設定
	ir_trx_flag = 1;
	
	// ------------------------------
	// リモコン読み取りタイムアウトタイマースタート
	// ------------------------------
	// タイマー0カウンタを初期化
	timer0_count = 0;
	// タイマー値設定
	TMR0H = timer0_h;
	TMR0L = timer0_l;
	// タイマー割り込みフラグ初期化
	INTCONbits.TMR0IF = 0;
	// タイマー0割り込み許可(=1) (Timer0 Overflow Interrupt Enable bit ... INTCON)
	INTCONbits.TMR0IE = 1; 
	// タイマー割り込み開始!!
	T0CON |= 0b10000000;
	// ------------------------------
	// ここまで
	// ------------------------------
	// ステータスLED点灯
	PORT_STATUS_LED = LED_ON;
	
	// ------------------------------
	// リモコンデータ受信サンプリングタイマースタート
	// ------------------------------
	// タイマー1カウンタを初期化
	timer1_count = 0;
	// タイマー値設定
	TMR1H = timer1_h;
	TMR1L = timer1_l;
	// タイマー割り込みフラグ初期化
	PIR1bits.TMR1IF = 0;
	// タイマー1割り込み許可(=1) (Timer1 Overflow Interrupt Enable bit ... PIE1)
	PIE1bits.TMR1IE = 1; 
	// タイマー割り込み開始!!
	T1CON |= 0b00000001;
	
	// 受信中はループ
	while (ir_trx_flag == 1)
	{
		Delay_10ms(1);    // 10ms待つ ←大事、判定用のフラグレジスタを破壊しないようにウェイト入れないとダメ 2013.12.03
	}
	
	send_strdata("ir_trx_flag = ");
	send_intdata(ir_trx_flag);
	send_crlf();
	send_strdata("IR COUNT = ");
	send_intdata(ir_count);
	send_crlf();
	send_strdata("DATA LENGTH = ");
	send_intdata(ir_data_len);
	send_crlf();
				
	send_strdata("--- IR RX END ---");
	send_crlf();
}

// ------------------------------
// IR JOB TX
// ------------------------------
void ir_job_tx(void)
{
	// メインバッファをI2Cメッセージポインタに設定
	gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
	// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
	ir_buffer = gvc_i2c_message->data;
	
	// リモコンデータ位置の初期化
	ir_count = 0;
	// リモコンデータビット位置の初期化
	ir_bit = 1;
	// 初回の送信ビットを設定(送信バイトと送信対象ビットをANDした値)
	ir_tx_data = *ir_buffer & ir_bit;
	// リモコン送信データの最後を設定
	ir_buffer_end = ir_buffer + ir_data_len;
	// リモコン送受信フラグを送信中(=2)に設定
	ir_trx_flag = 2;
	// 赤外線送信回数を初期化
	ir_tx_count = 1;
	
	// 受信開始を送信
	send_strdata("--- IR TX START ---");
	send_crlf();
	
	// サンプリング数を送信
	send_strdata("DATA LENGTH = ");
	send_intdata(ir_data_len);
	send_crlf();
	
	// 受信結果を送信
	send_strdata("STATUS = ");
	send_intdata(ir_rx_status);
	send_crlf();
	
	// 送信開始LED点灯
	PORT_RESULT_LED = LED_ON;
	
	// ------------------------------
	// リモコンデータ送信用PWMスタート
	// ------------------------------
	// PSTR1CON を設定(停止)
	PSTR1CON = 0b00010000;	// STR1SYNC = 1, STR1A = 0;
	// PWMの周期を設定(詳しくはデータシート参照)
	PR2 = 104;
	// PWMのデューティ比を設定(詳しくはデータシート参照)
	CCPR1L = 0b00100011;
	CCP1CON = 0b00111100;
	// PWMの初期値を設定(詳しくはデータシート参照)
	TMR2 = 104;
	// PWM用タイマー(TIMER2)をスタート(詳しくはデータシート参照)
	T2CON |= 0b00000100;
	
	// ------------------------------
	// リモコンデータ送信用タイマースタート
	// ------------------------------
	// タイマー1カウンタを初期化
	timer1_count = 0;
	// タイマー値設定
	TMR1H = timer1_h;
	TMR1L = timer1_l;
	// タイマー割り込みフラグ初期化
	PIR1bits.TMR1IF = 0;
	// タイマー1割り込み許可(=1) (Timer1 Overflow Interrupt Enable bit ... PIE1)
	PIE1bits.TMR1IE = 1; 
	// タイマー割り込み開始!!
	T1CON |= 0b00000001;
	
	// 送信中はループ
	while (ir_trx_flag == 2)
	{
		Delay_10ms(1);    // 10ms待つ ←大事、判定用のフラグレジスタを破壊しないようにウェイト入れないとダメ 2013.12.03
	}
	
	send_strdata("--- IR TX END ---");
	send_crlf();
}

// ------------------------------
// IR JOB SEND to Serial
// ------------------------------
void ir_job_send(void)
{
	// メインバッファをI2Cメッセージポインタに設定
	gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
	// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
	ir_buffer = gvc_i2c_message->data;
	
	// ------------------------------
	// リモコン読み取りデータをシリアルで送信
	// ------------------------------
	send_strdata("--- IR SEND SERIAL ---");
	send_crlf();
	
	// サンプリング数を送信
	send_strdata("DATA LENGTH = ");
	send_intdata(ir_data_len);
	send_crlf();
	
	// 受信結果を送信
	send_strdata("STATUS = ");
	send_intdata(ir_rx_status);
	send_crlf();
	
	// リモコンデータ送信処理
	send_ir_rxdata();
	
	send_strdata("--- IR SEND END ---");
	send_crlf();
}

// ------------------------------
// IR JOB DELETE
// ------------------------------
void ir_job_delete(void)
{
	// メインバッファをI2Cメッセージポインタに設定
	gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
	// メインバッファのdata[]ポインタをir_bufferとして改めて設定する
	ir_buffer = gvc_i2c_message->data;
	
	// ------------------------------
	// リモコン読み取りデータをシリアルで送信
	// ------------------------------
	send_strdata("--- IR DELETE START---");
	send_crlf();
	
	// リモコン受信状態を受信データなし(0)にする
	ir_rx_status = 0;
	// 赤外線データのデータ長をクリア
	ir_data_len = 0;
	// リモコンデータバッファのクリア
	memset((void *)ir_buffer, 0, IR_BUFF_SIZE);
	// 待避バッファもクリア
	memset((void *)ir_saved_buffer, 0, sizeof(ir_saved_buffer));
	
	send_strdata("--- IR DELETE END---");
	send_crlf();
}


// --------------------------------------------------
// Main loop
// --------------------------------------------------
void main(void)
{
	char rcv_data;							// 受信データ
	
	// Setup 18F26K22
	init_pic_18F26K22();
	
	// Setup MSSP1 18F26K22
	init_mssp1_18F26K22();
	
	// Setup EUSART 18F26K22
	init_eusart_18F26K22();
	
	// ----------------------------------------
	// これより下に、個別の設定を記述
	// ----------------------------------------
	// LED Brink
	led_brink(1);
	
	// ------------------------------
	// タイマー3設定
	// ------------------------------
	// bit 7-6 : TMRxCS<1:0>: Timer1/3/5 Clock Source Select bits
	//     11 =Reserved. Do not use.
	//     10 =Timer1/3/5 clock source is pin or oscillator:
	//         If TxSOSCEN = 0:
	//             External clock from TxCKI pin (on the rising edge)
	//         If TxSOSCEN = 1:
	//             Crystal oscillator on SOSCI/SOSCO pins
	//     01 =Timer1/3/5 clock source is system clock (FOSC)
	//     00 =Timer1/3/5 clock source is instruction clock (FOSC/4)
	// bit 5-4 : TxCKPS<1:0>: Timer1/3/5 Input Clock Prescale Select bits
	//     11 = 1:8 Prescale value
	//     10 = 1:4 Prescale value
	//     01 = 1:2 Prescale value
	//     00 = 1:1 Prescale value
	// bit 3   : TxSOSCEN: Secondary Oscillator Enable Control bit
	//     1 = Dedicated Secondary oscillator circuit enabled
	//     0 = Dedicated Secondary oscillator circuit disabled
	// bit 2   : TxSYNC: Timer1/3/5 External Clock Input Synchronization Control bit
	//     TMRxCS<1:0> = 1X
	//         1 = Do not synchronize external clock input
	//         0 = Synchronize external clock input with system clock (FOSC)
	//     TMRxCS<1:0> = 0X
	//         This bit is ignored. Timer1/3/5 uses the internal clock when TMRxCS<1:0> = 1X.
	// bit 1   : TxRD16: 16-Bit Read/Write Mode Enable bit
	//     1 = Enables register read/write of Timer1/3/5 in one 16-bit operation
	//     0 = Enables register read/write of Timer1/3/5 in two 8-bit operation
	// bit 0   : TMRxON: Timer1/3/5 On bit
	//     1 = Enables Timer1/3/5
	//     0 = Stops Timer1/3/5
	//     Clears Timer1/3/5 Gate flip-flop
	T3CON = 0b00100010;			// FOSC/4, 1:4, disabled, ignored, 16bit, Timer Stop
	
	// ------------------------------
	// タイマー3ゲート制御レジスタ設定
	// ------------------------------
	// bit 7 TMRxGE: Timer1 Gate Enable bit
	//     If TMRxON = 0:
	//         This bit is ignored
	//     If TMRxON = 1:
	//         1 = Timer1 counting is controlled by the Timer1 gate function
	//         0 = Timer1 counts regardless of Timer1 gate function
	// bit 6 T1GPOL: Timer1 Gate Polarity bit
	//     1 = Timer1 gate is active-high (Timer1 counts when gate is high)
	//     0 = Timer1 gate is active-low (Timer1 counts when gate is low)
	// bit 5 T1GTM: Timer1 Gate Toggle Mode bit
	//     1 = Timer1 Gate Toggle mode is enabled
	//     0 = Timer1 Gate Toggle mode is disabled and toggle flip-flop is cleared
	//     Timer1 gate flip-flop toggles on every rising edge.
	// bit 4 T1GSPM: Timer1 Gate Single-Pulse Mode bit
	//     1 = Timer1 gate Single-Pulse mode is enabled and is controlling Timer1 gate
	//     0 = Timer1 gate Single-Pulse mode is disabled
	// bit 3 T1GGO/DONE: Timer1 Gate Single-Pulse Acquisition Status bit
	//     1 = Timer1 gate single-pulse acquisition is ready, waiting for an edge
	//     0 = Timer1 gate single-pulse acquisition has completed or has not been started
	//     This bit is automatically cleared when T1GSPM is cleared.
	// bit 2 T1GVAL: Timer1 Gate Current State bit
	//     Indicates the current state of the Timer1 gate that could be provided to TMRxH:TMRxL.
	//     Unaffected by Timer1 Gate Enable (TMRxGE).
	// bit 1-0 T1GSS<1:0>: Timer1 Gate Source Select bits
	//     00 = Timer1 Gate pin
	//     01 = Timer0 overflow output
	//     10 = Comparator 1 optionally synchronized output (SYNCC1OUT)
	//     11 = Comparator 2 optionally synchronized output (SYNCC2OUT)(1)
	T3GCON = 0b00000000;		// ignored, active-low, disabled, disabled ...
	
	// Setup 18F26K22 for Analog Voltage
	init_pic_for_analogvoltage();
	
	// Get Vdd Voltage
	vdd_volt = get_vdd();
	// もしVddが4.0Vより大きいとか、1.0V未満なら
	if (vdd_volt > 4.0 || vdd_volt < 1.0)
	{
		// たぶんちゃんと測定できていないってことで、5.00に固定
		vdd_volt = 5.00;
	}
	
	// メインバッファをI2Cメッセージポインタに設定
	gvc_i2c_message = (GVC_I2C_MESSAGE_t *)main_buffer;
	// メインバッファのdata[]ポインタをir_bufferとする
	ir_buffer = gvc_i2c_message->data;
	
	// 各種グローバル変数の初期化…グローバル変数は宣言時に初期化していても実際にはしてくれない…orz 2013.07.11 T.Kabu
	rx_count = 0;							// 受信バッファ位置
	tx_count = 0;							// 送信バッファ位置
	i2c_status = 0;							// I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了
	ir_mode = 0;							// リモコンモジュール動作モード(0=受信データがあれば再送信、1=読み取り)
	ir_rxmax = 0;							// リモコン最大受信モード(0=通常、1=最大)
	ir_data = 0;							// リモコンデータ
//	ir_status = LED_OFF;					// リモコンデータのひとつ前の状態
	ir_status = PORT_IR_RX;					// リモコンデータのひとつ前の状態
	ir_bit = 1;								// リモコンデータビット位置
	ir_trx_flag = 0;						// リモコン送受信フラグ(0=none, 1=受信中, 2=送信中)
	ir_rx_status = 0;						// リモコン受信状態(0=none, 1=RXwait,2=RXing etc...)
	
	// タイマー値を初期化
	init_timer_18F26K22();

	// ----------------------------------------
	// 個別設定終了
	// ----------------------------------------
	
	// LED Brink
	led_brink(2);
	
	// 受信バッファポインタを初期化
	serial_rcvptr = 0;
	// 受信読み出しポインタを初期化
	serial_readptr = 0;
	
	// バッファを初期化
///	memset((void *)serial_rcvbuff, 0x00, sizeof(serial_rcvbuff));
	memset((void *)main_buffer, 0x00, sizeof(main_buffer));
	memset((void *)sub_buffer, 0x00, sizeof(sub_buffer));
	
	// EUSART1 RX 割り込み許可(=1) (EUSART1 Receive Interrupt Enable bit ... PIE1)
	PIE1bits.RC1IE = 1;
	// MSSP割り込み許可(=1) (Synchronous Serial Port (MSSP) Interrupt Enable bit ... PIE1)
	PIE1bits.SSP1IE = 1;
	// 周辺割り込み許可(=1) (Peripheral Interrupt Enable bit ... INTCON)
	INTCONbits.PEIE = 1;
	// 全割り込みを許可(=1) (Global Interrupt Enable bit ... INTCON)
	INTCONbits.GIE = 1;
	
	// バージョンを送信
	send_strdata(VERSION);
	send_crlf();
	
	// LED Brink
	led_brink(3);
	
	// メインループ
	while(1)
	{
		
		// シリアルバッファに未読データがないならスルー
		if (serial_rcvptr == serial_readptr)
		{
		}
		// あるなら
		else
		{
			// 受信バッファから一文字取得
			rcv_data = rcv_serialdata();
			
			// Rが来たら赤外線データ読み取りモードにする
			if (rcv_data == 'R')
			{
				send_strdata("R recieved.");
				send_crlf();
				// リモコン受信モードを通常(=0)に
				ir_rxmax = 0;
				// リモコンモードを読み取りモード(=1)に
				ir_mode = 1;
			}
			// Mが来たら赤外線データ最大読み取りモードにする
			else if (rcv_data == 'M')
			{
				send_strdata("M recieved.");
				send_crlf();
				// リモコン受信モードを最大(=1)に
				ir_rxmax = 1;
				// リモコンモードを読み取りモード(=1)に
				ir_mode = 1;
			}
			// Tが来たら赤外線データ送信モードにする
			else if (rcv_data == 'T')
			{
				send_strdata("T recieved.");
				send_crlf();
				// リモコンモードを再送信モード(=2)に
				ir_mode = 2;
			}
			// Sが来たら赤外線データシリアル出力モードにする
			else if (rcv_data == 'S')
			{
				send_strdata("S recieved.");
				send_crlf();
				// リモコンモードをシリアル出力モード(=3)に
				ir_mode = 3;
			}
			// DかCが来たら赤外線データを削除する
			else if (rcv_data == 'D')
			{
				send_strdata("D recieved.");
				send_crlf();
				// リモコンモードをデータ削除モード(=5)に
				ir_mode = 5;
			}
		}
		// もしリモコン(最大)読み取りモードなら
		if (ir_mode == 1)
		{
			// リモコン受信処理
			ir_job_rx();
			// リモコンデータシリアル送信処理
			ir_job_send();
			// リモコンモードをクリア
			ir_mode = 0;
		}
		// もしリモコン再送信モードなら
		if (ir_mode == 2)
		{
			// リモコン再送信処理
			ir_job_tx();
			// リモコンモードをクリア
			ir_mode = 0;
		}
		// もしリモコンデータ出力モードなら
		if (ir_mode == 3)
		{
			// リモコンデータシリアル送信処理
			ir_job_send();
			// リモコンモードをクリア
			ir_mode = 0;
		}
		// もしリモコンデータ削除モードなら
		if (ir_mode == 5)
		{
			// リモコンデータ削除処理
			ir_job_delete();
			// リモコンモードをクリア
			ir_mode = 0;
		}
	}
}