Funtion Decoder

###Overview
Smile Function Decoder　for NMRA Lib.
###Comment
dec/8/2018
Fix notifyDccReset processing.

１）Added initialization of gState_Fn variable.
//------------------------------------------------------------------
// Reset
//------------------------------------------------------------------
void notifyDccReset(uint8_t hardReset )
{
  digitalWrite(O1,LOW);
  digitalWrite(O2,LOW);
  digitalWrite(O3,LOW);
  digitalWrite(O4,LOW);

 　gState_F0 = 0; // ADD
 　gState_F1 = 0; // ADD
 　gState_F2 = 0; // ADD
 　gState_F3 = 0; // ADD
 　gState_F4 = 0; // ADD
 　gState_F5 = 0; // ADD
}

2）DCC reset pulse emulation added.
  if (Speed > 64) {
      doing_Resets_Flag = true;
      notifyDccReset(0);
  } else {
          doing_Resets_Flag = false;
    }


###link
https://twitter.com/masashi_214
http://ayabu.blog.shinobi.jp/
http://dcc.client.jp/
http://www007.upp.so-net.ne.jp/nagoden/


```c++
// 20181208 Kenneth west TEST Program ADD
//
// DCC Function Decoder Rev 2 for DS-DCC decode
// By yaasan
// Based on Nicolas's sketch http://blog.nicolas.cx
// Inspired by Geoff Bunza and his 17 Function DCC Decoder & updated library
// http://dcc.client.jp
// http://ayabu.blog.shinobi.jp
// O1:F3 でON/OFF head sign
// O2:F0 でON/OFF head light
// O3:F1 でON/OFF tail light
// O4:F5 でON/OFF room light

#include "NmraDcc.h"
#include <avr/eeprom.h>	 //required by notifyCVRead() function if enabled below

bool doing_Resets_Flag = false;  // True if we are simulating reset packets.

//FX効果
//Cmd,Time,Val,Frq
//I:初期状態,O:出力,S:スイープ,L:ループ,E:終了
unsigned char ptn1[2][3]={{'I',0,255},{'E',0,255}}; //10ms すぐ点灯
unsigned char ptn2[3][3]={{'I',0,5},{'S',100,255},{'E',0,255}}; //10ms もやっと点灯
unsigned char ptn3[4][3]={{'I',0,5},{'S',50,255},{'S',50,5},{'L',0,5}}; //10ms 三角波
unsigned char ptn4[6][3]={{'I',0,0},{'O',10,255},{'O',10,125},{'O',10,255},{'O',10,80},{'L',0,0}}; // ランダム
unsigned char ptn5[6][3]={{'I',0,0},{'S',50,255},{'S',50,0},{'S',50,128},{'S',50,0},{'L',0,0}};//マーズライト
unsigned char ptn6[4][3]={{'I',0,0},{'O',30,255},{'S',20,128},{'L',0,0}};//フラッシュライト
unsigned char ptn7[4][3]={{'I',0,0},{'O',20,255},{'O',80,0},{'L',0,0}}; //シングルパルスストロボ
unsigned char ptn8[6][3]={{'I',0,0},{'O',10,255},{'O',20,0},{'O',10,255},{'O',60,0},{'L',0,0}}; //ダブルパルスストロボ
unsigned char ptn9[6][3]={{'I',0,0},{'O',25,128},{'O',40,255},{'O',25,128},{'O',40,0},{'L',0,0}}; //ミディアムパルスストロボ
unsigned char ptn10[8][3]={{'I',0,0},{'O',1,255},{'O',1,0},{'O',1,255},{'O',30,0},{'O',10,50},{'O',100,255},{'E',0,0}}; //グロー管蛍光灯
unsigned char ptn11[9][3]={{'I',0,0},{'O',1,255},{'O',1,0},{'O',1,255},{'O',30,0},{'O',30,40},{'O',50,255},{'O',70,0},{'L',0,0}}; //グロー管蛍光灯切れそう
unsigned char (*ptn)[3];

//各種設定、宣言

#define DECODER_ADDRESS 3
#define DCC_ACK_PIN 0   // Atiny85 PB0(5pin) if defined enables the ACK pin functionality. Comment out to disable.
//                      // Atiny85 DCCin(7pin)
#define O1 0            // Atiny85 PB0(5pin)             head sign light
#define O2 1            // Atiny85 PB1(6pin) analogwrite Head light
#define O3 3            // Atint85 PB3(2pin)             tail light
#define O4 4            // Atiny85 PB4(3pin) analogwrite room light

#define MAX_PWMDUTY 255
#define MID_PWMDUTY 10

#define CV_VSTART		2
#define CV_ACCRATIO		3
#define CV_DECCRATIO	4
#define CV_F0_FORWARD 33
#define CV_F0_BACK 34
#define CV_F1 35
#define CV_F2 36
#define CV_F3 37
#define CV_F4 38
#define CV_F5 39
#define CV_F6 40
#define CV_F7 41
#define CV_F8 42
#define CV_F9 43
#define CV_F10 44
#define CV_F11 45
#define CV_F12 46
#define CV_49_F0_FORWARD_LIGHT 49
#define CV_DIMMING_SPEED 50
#define CV_DIMMING_LIGHT_QUANTITY 51
#define CV_ROOM_DIMMING 52

//ファンクションの変数
uint8_t fn_bit_f0 = 0;
uint8_t fn_bit_f1 = 0;
uint8_t fn_bit_f2 = 0;
uint8_t fn_bit_f3 = 0;
uint8_t fn_bit_f4 = 0;
uint8_t fn_bit_f5 = 0;
uint8_t fn_bit_f6 = 0;
uint8_t fn_bit_f7 = 0;
uint8_t fn_bit_f8 = 0;
uint8_t fn_bit_f9 = 0;
uint8_t fn_bit_f10 = 0;
uint8_t fn_bit_f11 = 0;
uint8_t fn_bit_f12 = 0;
uint8_t fn_bit_f13 = 0;
uint8_t fn_bit_f14 = 0;
uint8_t fn_bit_f15 = 0;
uint8_t fn_bit_f16 = 0;
uint8_t fn_bit_f17 = 0;
uint8_t fn_bit_f18 = 0;
uint8_t fn_bit_f19 = 0;
uint8_t fn_bit_f20 = 0;
uint8_t fn_bit_f21 = 0;
uint8_t fn_bit_f22 = 0;
uint8_t fn_bit_f23 = 0;
uint8_t fn_bit_f24 = 0;
uint8_t fn_bit_f25 = 0;
uint8_t fn_bit_f26 = 0;
uint8_t fn_bit_f27 = 0;
uint8_t fn_bit_f28 = 0;

//使用クラスの宣言
NmraDcc	 Dcc;
DCC_MSG	 Packet;

//Task Schedule
unsigned long gPreviousL5 = 0;

//進行方向
uint8_t gDirection = 128;

//Function State
uint8_t gState_F0 = 0;
uint8_t gState_F1 = 0;
uint8_t gState_F2 = 0;
uint8_t gState_F3 = 0;
uint8_t gState_F4 = 0;
uint8_t gState_F5 = 0;
uint8_t gState_F6 = 0;
uint8_t gState_F7 = 0;
uint8_t gState_F8 = 0;
uint8_t gState_F9 = 0;
uint8_t gState_F10 = 0;
uint8_t gState_F11 = 0; 
uint8_t gState_F12 = 0;
//モータ制御関連の変数
uint32_t gSpeedRef = 1;

//CV related
uint8_t gCV1_SAddr = 3; 
uint8_t gCVx_LAddr = 3;
uint8_t gCV49_fx = 20;
uint8_t gCV50_DimmingSpeed = 1;
uint8_t gCV51_DimmingLightQuantity = 10;
uint8_t gCV52_RoomDimming = 128;

//Internal variables and other.
#if defined(DCC_ACK_PIN)
const int DccAckPin = DCC_ACK_PIN ;
#endif

struct CVPair {
  uint16_t	CV;
  uint8_t	Value;
};
CVPair FactoryDefaultCVs [] = {
  {CV_MULTIFUNCTION_PRIMARY_ADDRESS, DECODER_ADDRESS}, // CV01
  {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},               // CV09 The LSB is set CV 1 in the libraries .h file, which is the regular address location, so by setting the MSB to 0 we tell the library to use the same address as the primary address. 0 DECODER_ADDRESS
  {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},          // CV17 XX in the XXYY address
  {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},          // CV18 YY in the XXYY address
  {CV_29_CONFIG, 128 },                                // CV29 Make sure this is 0 or else it will be random based on what is in the eeprom which could caue headaches
  {CV_49_F0_FORWARD_LIGHT, 20},                        // CV49 F0 Forward Light
  {CV_DIMMING_SPEED, 1},
  {CV_DIMMING_LIGHT_QUANTITY,10},
  {CV_ROOM_DIMMING, 100},
};

void(* resetFunc) (void) = 0;  //declare reset function at address 0
void LightMes( char,char );
void pulse(void);
uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs) / sizeof(CVPair);

void notifyDccReset(uint8_t hardReset );

//uint16_t limitSpeed(uint16_t inSpeed);

void notifyCVResetFactoryDefault()
{
  //When anything is writen to CV8 reset to defaults.

  resetCVToDefault();
  //Serial.println("Resetting...");
  delay(1000);  //typical CV programming sends the same command multiple times - specially since we dont ACK. so ignore them by delaying

  resetFunc();
};

//------------------------------------------------------------------
// Reset
//------------------------------------------------------------------
void notifyDccReset(uint8_t hardReset )
{
  digitalWrite(O1,LOW);
  digitalWrite(O2,LOW);
  digitalWrite(O3,LOW);
  digitalWrite(O4,LOW);

 　gState_F0 = 0; // ADD
 　gState_F1 = 0; // ADD
 　gState_F2 = 0; // ADD
 　gState_F3 = 0; // ADD
 　gState_F4 = 0; // ADD
 　gState_F5 = 0; // ADD
}

//------------------------------------------------------------------
// CVをデフォルトにリセット
// Serial.println("CVs being reset to factory defaults");
//------------------------------------------------------------------
void resetCVToDefault()
{
  for (int j = 0; j < FactoryDefaultCVIndex; j++ ) {
    Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
  }
};



extern void	   notifyCVChange( uint16_t CV, uint8_t Value) {
  //CVが変更されたときのメッセージ
  //Serial.print("CV ");
  //Serial.print(CV);
  //Serial.print(" Changed to ");
  //Serial.println(Value, DEC);
};

//------------------------------------------------------------------
// CV Ack
//------------------------------------------------------------------
void notifyCVAck(void)
{
  //Serial.println("notifyCVAck");
  digitalWrite(O1,HIGH);
  digitalWrite(O2,HIGH);
  digitalWrite(O3,HIGH);
  digitalWrite(O4,HIGH);

  delay( 6 );

  digitalWrite(O1,LOW);
  digitalWrite(O2,LOW);
  digitalWrite(O3,LOW);
  digitalWrite(O4,LOW);
}

//------------------------------------------------------------------
// Arduino固有の関数 setup() :初期設定
//------------------------------------------------------------------
void setup()
{
  //シリアル通信開始
  //Serial.begin(115200);

  //D9,D10 PWM キャリア周期:31kHz
//  TCCR1 &= B11110000;
//  TCCR1 |= B00000001;

  //PWMを10bit化
  //TCCR1A |= B00000011;

//    TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
 //   TCCR0B = 0<<WGM02 | 1<<CS00;    
 //   TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
 //   GTCCR = 1<<PWM1B | 2<<COM1B0;
#if 0
  TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00; // B1111 0011
  TCCR0B = 0<<WGM02 | 1<<CS00;               // B0000 0001 分周無し
  TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
  GTCCR = 1<<PWM1B | 2<<COM1B0;  
#endif

// TCCR1 =0x03;最初に0x03が設定されている。
// D9,D10 PWM キャリア周期:31kHz
// TCCR1 &= B11110000;
// TCCR1 |= B00000001;

//TCCR1 = 1<<CTC1 | 1<<PWM1A | 3<<COM1A0 | 1<<CS10;
  TCCR1 = 0<<CTC1 | 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
  
  pinMode(O1, OUTPUT);
  pinMode(O2, OUTPUT);
  pinMode(O3, OUTPUT);
  pinMode(O4, OUTPUT);

  //DCCの応答用負荷ピン
#if defined(DCCACKPIN)
  //Setup ACK Pin
  pinMode(DccAckPin, OUTPUT);
  digitalWrite(DccAckPin, 0);
#endif

#if !defined(DECODER_DONT_DEFAULT_CV_ON_POWERUP)
  if ( Dcc.getCV(CV_MULTIFUNCTION_PRIMARY_ADDRESS) == 0xFF ) {	 //if eeprom has 0xFF then assume it needs to be programmed
    //Serial.println("CV Defaulting due to blank eeprom");
    notifyCVResetFactoryDefault();

  } else {
    //Serial.println("CV Not Defaulting");
  }
#else
  //Serial.println("CV Defaulting Always On Powerup");
  notifyCVResetFactoryDefault();
#endif

  // Setup which External Interrupt, the Pin it's associated with that we're using, disable pullup.
  Dcc.pin(0, 2, 0); // Atiny85 7pin(PB2)をDCC_PULSE端子に設定

  // Call the main DCC Init function to enable the DCC Receiver
  Dcc.init( MAN_ID_DIY, 100,   FLAGS_MY_ADDRESS_ONLY , 0 );

  //Reset task
  gPreviousL5 = millis();

  //Init CVs
  gCV1_SAddr = Dcc.getCV( CV_MULTIFUNCTION_PRIMARY_ADDRESS ) ;

//#if 0
  gCV49_fx = Dcc.getCV( CV_49_F0_FORWARD_LIGHT );
  switch(gCV49_fx){
    case 0: ptn = ptn1;
    break;
    case 1: ptn = ptn1;
    break;
    case 2: ptn = ptn2;
    break;
    case 3: ptn = ptn3;    
    break;
    case 4: ptn = ptn4;
    break;
    case 5: ptn = ptn5;
    break;
    case 6: ptn = ptn6;
    break;
    case 7: ptn = ptn7;
    break;
    case 8: ptn = ptn8;
    break;
    case 9: ptn = ptn9;
    break;
    case 10: ptn = ptn10;
    break;
    case 11: ptn = ptn11;
    break;
  }
  gCV50_DimmingSpeed  = Dcc.getCV( CV_DIMMING_SPEED );          // 減光スピード
  gCV51_DimmingLightQuantity = Dcc.getCV( CV_DIMMING_LIGHT_QUANTITY );  // 減光レベル
  gCV52_RoomDimming = Dcc.getCV( CV_ROOM_DIMMING );
//#endif

//デバック信号：起動 　
//注意：2016/4/9 このコメントを外し起動時にアドレスを点灯させるようにすると、
//      loopにたどり着く時間が長くなり、CV書き込みが失敗します。
//LightMes(0);
//LightMes(Dcc.getCV(CV_MULTIFUNCTION_PRIMARY_ADDRESS));
//LightMes(gCV49_fx,8);

//O2 analog test 明るく点灯ぃて１秒後に暗くなる
//OCR1A有効   high出力          分周無し　
#if 0
TCCR1 = 1<<PWM1A | 2<<COM1A0 | 1<<CS10; 
OCR1A = 255;
delay(1000);
OCR1A = 12;
for(;;);
#endif
}

//---------------------------------------------------------------------
// Arduino main loop
//---------------------------------------------------------------------
void loop() {
  // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
  Dcc.process();

  if ( (millis() - gPreviousL5) >= 10) // 100:100msec  10:10msec  Function decoder は 10msecにしてみる。
  {
    //Headlight control
    HeadLight_Control();

    //Motor drive control
    //Motor_Control();

    //Reset task
    gPreviousL5 = millis();
  }
}


//---------------------------------------------------------------------
// HeadLight control Task (10Hz:100ms)
//---------------------------------------------------------------------
void HeadLight_Control()
{
  uint16_t aPwmRef = 0;

  if((gCV49_fx >= 2) && (gCV49_fx <= 11)) {
    FXeffect_Control();
  }

//---------------------------------------------------------------------
// ヘッド・テールライトコントロール
// CV49=20 設定で有効
// F0 で　On/Off O2:head O3:tail 
//--------------------------------------------------------------------- 
  if(gCV49_fx == 20) {
    if(gState_F0 > 0) {
      if( gDirection == 0){                // Reverse 後進(DCS50Kで確認)

        TCCR1 = 1<<CS10;            // OCR1A 無効
        OCR1A = 0;                  // O2:analog out (hedd light) 
        digitalWrite(O3, HIGH);            // 点灯
   
      } else {                             // Forward 前進(DCS50Kで確認)
        digitalWrite(O3, LOW);             // O3:tail light off
        //               OCR1A有効   high出力          分周無し　
        TCCR1 = 1<<PWM1A | 2<<COM1A0 | 1<<CS10; 
        
        if ( gSpeedRef > 1 ){//gCV50_DimmingSpeed ){    // 調光機能
          aPwmRef = MAX_PWMDUTY;          // 速度が1以上だったらMAX
        } else {
          aPwmRef = 10;//gCV51_DimmingLightQuantity;    // 減光レベル
        }

        OCR1A = aPwmRef;                  // O2:analog out (hedd light)
      }
    }
  
    if(gState_F0 == 0){                   // DCC F0 コマンドの処理
      TCCR1 = 1<<CS10; 
      OCR1A = 0;                          // O2:analog out (hedd light) 
      digitalWrite(O2, LOW);              // 消灯
      digitalWrite(O3, LOW);              // 消灯
    }
  }


//---------------------------------------------------------------------
// ヘッド・テールライトコントロール
// CV49=21 設定で有効
// F0 で　On/Off O2:head O3:tail 
//--------------------------------------------------------------------- 
  if(gCV49_fx == 21) {
    if(gState_F0 > 0) {
      if( gDirection == 1){                // Reverse 前進(DCS50Kで確認)
        digitalWrite(O2, HIGH);
        digitalWrite(O3, LOW);
      } else {                             // Forward 後進(DCS50Kで確認)
        digitalWrite(O2, LOW);
        digitalWrite(O3, HIGH);
      }
    }
    if(gState_F0 == 0) {
        digitalWrite(O2, LOW);  
        digitalWrite(O3, LOW);
    }
  }

//---------------------------------------------------------------------
// ヘッド・テールライトコントロール
// CV49=0,1 設定で有効
// F0 で　Head Light On/Off F1 Tail Light On/Off F3 HEAD sign F5 room 
//--------------------------------------------------------------------- 
 
// F0 受信時の処理
//#if 
  if((gCV49_fx != 20)||(gCV49_fx != 20)) {
    if(gState_F0 == 0){
      digitalWrite(O2, LOW);
    } else {
      digitalWrite(O2, HIGH);
    }
//#endif
    
// F1 受信時の処理
//#if 
    if(gState_F1 == 0){
      digitalWrite(O3, LOW);
    } else {
      digitalWrite(O3, HIGH);
    }
//#endif  
  }

//---------------------------------------------------------------------
// ヘッド・テールライトコントロール
// F3 と F5の処理
//--------------------------------------------------------------------- 

// F2 受信時の処理
// DCS50KのF2は1shotしか光らないので、コメントアウト
#if 0 
  if(gCV49_fx < 20 ) {  // CV49 が20 または21 以外有効
    if(gState_F2 == 0){                   
      digitalWrite(O2, LOW);  
    } else {
      digitalWrite(O2, HIGH);
    }
  }
#endif

// F3 受信時の処理
//#if 0
  if(gState_F3 == 0){
    digitalWrite(O1, LOW);
  } else {
    digitalWrite(O1, HIGH);
  }
//#endif

// F4 受信時の処理
#if 0
  if(gState_F4 == 0){
    digitalWrite(O4, LOW);
  } else {
    digitalWrite(O4, HIGH);
  }
#endif

// F5 受信時の処理
  if(gState_F5 == 0){
    GTCCR = 0 << PWM1B | 0 << COM1B0;
    analogWrite(O4, 0);
    digitalWrite(O4, LOW);               // 消灯
  } else {
    GTCCR = 1 << PWM1B | 2 << COM1B0;
    analogWrite(O4,gCV52_RoomDimming);
  }
}



//DCC速度信号の受信によるイベント
//extern void notifyDccSpeed( uint16_t Addr, uint8_t Speed, uint8_t ForwardDir, uint8_t MaxSpeed )
extern void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
{
  if (Speed > 64) {
//  if(doing_Resets_Flag == false) {
      doing_Resets_Flag = true;
      notifyDccReset(0);
//    }
  }
    else {
          doing_Resets_Flag = false;
    }


  
//  if ( gDirection != ForwardDir) // old NMRA
  if ( gDirection != Dir )
  {
//  gDirection = ForwardDir; // old NMRA
    gDirection = Dir;
  }
  gSpeedRef = Speed;
}




//---------------------------------------------------------------------
// FX効果ステートマシン
// 10ms周期で起動
// unsigned chart ptn[4][5]{{'I',0,0,1},{'S',20,255,1},{'S',40,0,1},{'E',0,0,1}};
//---------------------------------------------------------------------
void FXeffect_Control(){
  static char state = 0;    // ステート
  static unsigned char adr = 0;      // アドレス
  static int timeUp = 0;    // 時間
  static float delt_v = 0;  // 100msあたりの増加量 
  static float pwmRef =0;

  if(gState_F0 == 0){ // F0 OFF
    state = 0; 
    adr = 0;
    timeUp = 0;
    pwmRef = 0;
    // OCR1A無効   OCR1A未使用　 分周無し O2:消灯させる　
    TCCR1 = 1<<CS10; 
    digitalWrite(O2, LOW); // PB1:O2:6pin LOW出力
  }

  S00:  
  switch(state){
    case 0: // S00:idel
      if(gState_F0 >0){ // F0 ON
        adr = 0;
        timeUp = 0;
        pwmRef = 0;
        //               OCR1A有効   high出力          分周無し　
        TCCR1 = 1<<PWM1A | 2<<COM1A0 | 1<<CS10; 
        OCR1A = 0;
        state = 1;
        goto S00;     // 100ms待たずに再度ステートマシーンに掛ける
      }
      break;
      
    case 1: // S01:コマンド処理
        if( ptn[adr][0]=='I'){ // I:初期化
          timeUp = ptn[adr][1];
          pwmRef = ptn[adr][2];
          delt_v = 0; // 変化量0
          OCR1A = (unsigned char)pwmRef;                  // O2:analog out (hedd light)
          adr++;
          state = 1;
          goto S00;   // 100ms待たずに再度ステートマシーンに掛ける
        } else if( ptn[adr][0]=='E'){ // E:end
          state = 3;
        } else if( ptn[adr][0]=='L' ){  // L:Loop
          adr = 0;
          state =1;
          goto S00;   // 100ms待たずに再度ステートマシーンに掛ける
        } else if( ptn[adr][0]=='O' ){ // O:出力
          timeUp = ptn[adr][1];
          pwmRef = ptn[adr][2];
          delt_v = 0;
          state = 2;          
        } else if( ptn[adr][0]=='S' ){ // S:sweep
          timeUp = ptn[adr][1];
          delt_v = (ptn[adr][2]-pwmRef)/timeUp;  // 変化量を算出
          state = 2;
        }
      break;
      
    case 2: // S02:時間カウント
      timeUp--;
      pwmRef = pwmRef + delt_v;
      if(pwmRef<=0){            // 下限、上限リミッタ
          pwmRef = 0;
      } else if(pwmRef>=255){
          pwmRef = 255;
      }
      OCR1A = (unsigned char)pwmRef;                  // O2:analog out (hedd light) 
      if( timeUp <= 0 ){
        adr ++;
        state = 1;  //次のコマンドへ
      }
      break;

      case 3: // stay
      break;

      default:
      break;
  }
}





//---------------------------------------------------------------------------
//ファンクション信号受信のイベント
//FN_0_4とFN_5_8は常時イベント発生（DCS50KはF8まで）
//FN_9_12以降はFUNCTIONボタンが押されたときにイベント発生
//前値と比較して変化あったら処理するような作り。
//---------------------------------------------------------------------------
//extern void notifyDccFunc( uint16_t Addr, FN_GROUP FuncGrp, uint8_t FuncState)
extern void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
{
  if ( doing_Resets_Flag == true ) {
    return;
  }


  if( FuncGrp == FN_0_4)
  {
    if( gState_F0 != (FuncState & FN_BIT_00))
    {
      //Get Function 0 (FL) state
      gState_F0 = (FuncState & FN_BIT_00);
    }
    if( gState_F1 != (FuncState & FN_BIT_01))
    {
      //Get Function 1 state
      gState_F1 = (FuncState & FN_BIT_01);
    }
    if( gState_F2 != (FuncState & FN_BIT_02))
    {
      gState_F2 = (FuncState & FN_BIT_02);
    }
    if( gState_F3 != (FuncState & FN_BIT_03))
    {
      gState_F3 = (FuncState & FN_BIT_03);
    }
    if( gState_F4 != (FuncState & FN_BIT_04))
    {
      gState_F4 = (FuncState & FN_BIT_04);
    }
  }

  if( FuncGrp == FN_5_8)
  {
    if( gState_F5 != (FuncState & FN_BIT_05))
    {
      //Get Function 0 (FL) state
      gState_F5 = (FuncState & FN_BIT_05);
    }
    if( gState_F6 != (FuncState & FN_BIT_06))
    {
      //Get Function 1 state
      gState_F6 = (FuncState & FN_BIT_06);
    }
    if( gState_F7 != (FuncState & FN_BIT_07))
    {
      gState_F7 = (FuncState & FN_BIT_07);
    }
    if( gState_F8 != (FuncState & FN_BIT_08))
    {
      gState_F8 = (FuncState & FN_BIT_08);
    }
  }

   
}

//-----------------------------------------------------
// F4 を使って、メッセージを表示させる。
//上位ビットから吐き出す
// ex 5 -> 0101 -> ー・ー・
//-----------------------------------------------------
void LightMes( char sig ,char set)
{
  char cnt;
  for( cnt = 0 ; cnt<set ; cnt++ ){
    if( sig & 0x80){
      digitalWrite(O1, HIGH); // 短光
      delay(200);
      digitalWrite(O1, LOW);
      delay(200);
    } else {
      digitalWrite(O1, HIGH); // 長光
      delay(1000);
      digitalWrite(O1, LOW);            
      delay(200);
    }
    sig = sig << 1;
  }
      delay(400);
}

//-----------------------------------------------------
// Debug用Lﾁｶ
//-----------------------------------------------------
void pulse()
{
  digitalWrite(O1, HIGH); // 短光
  delay(100);
  digitalWrite(O1, LOW);
}