Arduinoでクラスを使ったファンクションデコーダ（随時バージョンアップ）

###概要
Arduinoで、ステートマシーンを使ってファンクションデコーダを設計中
12FXもあるので、OPPのクラスを使って設計中
なんとなく、仮想関数を使ってみた。
***
###動作
・LEDのグループ
・常時点灯モード
・Forward/Reverseによる区別
・調光を実装
***
###今後
Forward/Reverseによる調光で混乱中(^^;
シーケンス点灯を実装
***
```c++:StateMachine.cpp
#include "Arduino.h"
#include "StateMachine.h"
//#include "ini.h"
#include "define.h"
#include "NmraDcc.h"

extern uint8_t g_Direction;
extern uint8_t g_SpeedRef;

// コンストラクタ（初期化処理）
state_machine::state_machine(uint8_t fn, uint8_t og, uint8_t fc, uint8_t di, uint8_t st) // fn:gState_F1 og:gCV35_OL fc:gCV49_FC di:gCV112_FC st:gCV126_FC
{
    FunctionCommand = fn;
    FunctionGroup = og;
    FunctionConfig = fc;
    Dimm = di;
    SpeedThreshold = st;
    state = ST_IDLE;
}

void state_machine::StateCheck()
{
  static l_Dir;
  
  switch(state){
    case ST_NONE:
                  break;
    case ST_IDLE:
                  if(FunctionConfig & ALWAYS){          // 常に点灯ビットon?
                    state = ST_ALWAYSON;
                    break;
                  }
                  if(FunctionCommand > 0) {           // F1 = ON?
                    if(FunctionConfig & DIRCON) {       // For/Rev 有効フラグ？
                        if(FunctionConfig & FORREV) {   // Reverse ?
                          if( g_Direction == REVERSE){ // Reverse 後進(DCS50Kで確認)                         
                            if(FunctionConfig & DIMCON) { // 調光あり？
                              state = ST_RUN_Lo;
                            } else {
                              state = ST_RUN_Hi;
                            }
                          }
                        } else {
                          if( g_Direction == FORWARD ){ // Forward 前進
                            state = ST_RUN;
                          }                          
                        }
                    }
                    state = ST_RUN;    
                  }
                  break;
                  
    case ST_ALWAYSON:                                 // 常に点灯処理
                  high();
                  state = ST_NONE;
                  break;                  
 
    case ST_RUN_Lo:
                  l_Dir = g_Direction;                // 現在のFor/Revを記録
                  dimming(Dimm & 0x0f);
                  state = ST_RUN_Lo_STAY;
                  break;
                  
    case ST_RUN_Lo_STAY:                              // 調光あり状態
                  if( g_SpeedRef > SpeedThreshold ){
                    state = ST_RUN_Hi;
                    break;
                  }
                  if(FunctionConfig & DIRCON) {       // For/Rev 有効フラグ？
                      if(FunctionConfig & FORREV) {   // Reverse ?
                        state = ST_RSTAY;
                      } else {
                        state = ST_FSTAY;                      
                      }
                  } else {                  
                    state = ST_STAY;  
                  }
                  break;
                  
    case ST_RUN_Hi:   // 今んところ点灯するだけ
                  high();
                  if(FunctionConfig & DIRCON) {       // For/Rev 有効フラグ？
                      if(FunctionConfig & FORREV) {   // Reverse ?
                        state = ST_RSTAY;
                      } else {
                        state = ST_FSTAY;                      
                      }
                  } else {                  
                    state = ST_STAY;  
                  }
                  break;    
    case ST_FSTAY:                             // 前進点灯状態
                  if( g_Direction == 0 ){       // Reverse 後進(DCS50Kで確認)                         
                    state = ST_STOP;
                  }
                  if( FunctionCommand == 0 ) {
                    state = ST_STOP;
                  }
                  break;
    case ST_RSTAY:                             // 後進点灯状態
                  if( g_Direction > 0){        // Forward 前進                         
                    state = ST_STOP;
                  }
                  if( FunctionCommand == 0 ) {
                    state = ST_STOP;
                  }
                  break;
    case ST_STAY:
                  if( FunctionCommand == 0 ) {
                    state = ST_STOP;
                  }
                  break;
    case ST_STOP:
                  low();
                  state = ST_IDLE;  
                  break;
    default:
                  break;
  }
}

void state_machine::low(){};
void state_machine::high(){};
void state_machine::dimming(uint8_t){};
```

```cpp:StateMachine.h
#ifndef _STATEMACHINE_H_
#define _STATEMACHINE_H_

// クラスの定義
class state_machine {
  enum{
    ST_NONE = 0,
    ST_IDLE,
    ST_ALWAYSON, // 常に点灯
    ST_ALWATSON_STAY,
    ST_RUN,
    ST_RUN_Lo,     // low点灯
    ST_RUN_Lo_STAY,
    ST_RUN_Hi,     // high点灯
    ST_RUN_Hi_STAY,
    ST_STAY,     // 点灯状態を保持
    ST_FSTAY,    // 前進保持
    ST_RSTAY,    // 後進保持
    ST_STOP      // 消灯
  };

private:
  uint8_t state;
  uint8_t FunctionConfig;
  uint8_t FunctionCommand;
  uint8_t Direction;
  uint8_t cnt;
  uint8_t FuncPort;
  uint8_t Dimm;
 
  virtual void low();
  virtual void high();
  virtual void dimming(uint8_t);

public:
  uint8_t FunctionGroup;
  state_machine(uint8_t og, uint8_t fc, uint8_t fn, uint8_t di,  uint8_t st,uint8_t dr );
  void StateCheck();
};
#endif// _STATEMACHINE_H_
```
```cpp:fnf-3.h
//
// Forward Headlight,Function 1,2,3 のグループ
// Bi1 PWM , Bi2 PWM , AUX1 PWM , AUX2 PWM , AUX3 PWM
// 速度のイベントが設定できるグループ
//

#ifndef _FNF3_H_
#define _FNF3_H_

#include "StateMachine.h"
#include "define.h"


//uint8_t dimm[16]={0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255};
uint8_t DIMMx[16]={0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd , 0xee, 0xff};


class CFnf_3 : public state_machine{
private:
  void low();
  void high();
  void dimming(uint8_t);
  
public:
    CFnf_3(uint8_t og, uint8_t fc, uint8_t fn , uint8_t di, uint8_t dr ):state_machine(og,fc,fn,di,dr){};
};

void CFnf_3::low()
{
  if(FunctionGroup & 0x01)
    digitalWrite(Bi1,LOW);
  if(FunctionGroup & 0x02)
    digitalWrite(Bi2,LOW);
  if(FunctionGroup & 0x04)
    digitalWrite(AUX1,LOW);
  if(FunctionGroup & 0x08)
    digitalWrite(AUX2,LOW);
  if(FunctionGroup & 0x10)
    digitalWrite(AUX3,LOW);
  if(FunctionGroup & 0x20)
    digitalWrite(AUX4,LOW);  
  if(FunctionGroup & 0x40)
    digitalWrite(AUX5,LOW);  
  if(FunctionGroup & 0x80)
    digitalWrite(AUX6,LOW);  
}

void CFnf_3::high()
{
  if(FunctionGroup & 0x01)
    digitalWrite(Bi1,HIGH);
  if(FunctionGroup & 0x02)
    digitalWrite(Bi2,HIGH);
  if(FunctionGroup & 0x04)
    digitalWrite(AUX1,HIGH);
  if(FunctionGroup & 0x08)
    digitalWrite(AUX2,HIGH);
  if(FunctionGroup & 0x10)
    digitalWrite(AUX3,HIGH);
  if(FunctionGroup & 0x20)
    digitalWrite(AUX4,HIGH);  
  if(FunctionGroup & 0x40)
    digitalWrite(AUX5,HIGH);  
  if(FunctionGroup & 0x80)
    digitalWrite(AUX6,HIGH);  
}

void CFnf_3::dimming(uint8_t di)
{
  if(FunctionGroup & 0x01)
    analogWrite(Bi1,DIMMx[di]);    // analog
  if(FunctionGroup & 0x02)
    analogWrite(Bi2,DIMMx[di]);    // analog
  if(FunctionGroup & 0x04)
    analogWrite(AUX1,DIMMx[di]);   // analog
  if(FunctionGroup & 0x08)
    analogWrite(AUX2,DIMMx[di]);   // analog
  if(FunctionGroup & 0x10)
    analogWrite(AUX3,DIMMx[di]);   // analog
  if(FunctionGroup & 0x20)
    analogWrite(AUX4,DIMMx[di]);   // analog  
  if(FunctionGroup & 0x40)
    digitalWrite(AUX5,DIMMx[di]);   // digital  
  if(FunctionGroup & 0x80)
    digitalWrite(AUX6,DIMMx[di]);   // digital  
}
 
#endif // _FNF3_H_
```

```cpp:ini.h
//http://www.bitsavers.org/pdf/chromatics/CGC_7900_C_Programmers_Manual_Mar82.pdf
//https://www.nmra.org/sites/default/files/standards/sandrp/pdf/s-9.2.2_decoder_cvs_2012.07.pdf
//http://www.snjpn.com/ngdcc/docs/DF19x4bp_CVLIST.pdf

uint8_t gCV1_SAddr = 3; 

uint8_t gCV7_ManVer = 0;      // Manufacturer Version No. 
uint8_t gCV8_ManId = 0x0d;    // Manufactured ID : Public Domain & Do-It-Yourself Decoders
//                +--------0:Mulifunction Decoder 1:Accessory Decoder
//                |+-------0:
//                ||+------0:2digit address 1:4digt address 
//                |||+-----0:speed table off 1:speed table on
//                ||||+----
//                |||||+---0:analog off 1:analog on   
//                ||||||+--0:14step 1:28/9128step
//                |||||||+-0:normal 1:reversed
uint8_t gCV29 = 0b10000000;

// CV33-46 Output Location（グループ）
//        (MSB)edcba987654321(LSB)
//                   87654321
uint8_t gCV33_OL = 0b00000001;   // Forward Headlinght FL(f)
uint8_t gCV34_OL = 0b00000010;   // Reverse Headlinght FL(r)
uint8_t gCV35_OL = 0b00000100;   // Function 1
uint8_t gCV36_OL = 0b00001000;   // Function 2
uint8_t gCV37_OL = 0b00010000;   // Function 3

//                   ba987654
uint8_t gCV38_OL = 0b00000100;   // Function 4
uint8_t gCV39_OL = 0b00001000;   // Function 5
uint8_t gCV40_OL = 0b00010000;   // Function 6
uint8_t gCV41_OL = 0b00100000;   // Function 7
uint8_t gCV42_OL = 0b01000000;   // Function 8
//                   edcba987
uint8_t gCV43_OL = 0b00010000;   // Function 9
uint8_t gCV44_OL = 0b00100000;   // Function 10
uint8_t gCV45_OL = 0b01000000;   // Function 11
uint8_t gCV46_OL = 0b10000000;   // Function 12

// CV47- Function Config
// 
//                   +--------0x80 0:fb3 1001:patern10 , 1010:patern11 , 1011:patern12 , 1100:patern13 , 1101:14 , 1110:15, 1111:patern16パンタスパーク
//                   |+-------0x40 0:fb2 0101:patern6 , 0110:patern7 , 0111:patern8 , 1000:patern9
//                   ||+------0x20 0:fb1 0001:patern2 , 0010:patern3 , 0011:patern4 , 0100:patern5  
//                   |||+-----0x10 0:fb0 0000:patern1 
//                   ||||+----0x08 0:Event調光無効 1:Event調光有効
//                   |||||+---0x04 0:Disable 1:enable (方向制御For/Rev) 
//                   ||||||+--0x02 0:Forward 1:Reverse 
//                   |||||||+-0x01 0:normal 1:常に点灯
//                   ||||||||
uint8_t gCV47_FC = 0b00000000;   // Forward Headlinght FL(f)
uint8_t gCV48_FC = 0b00000000;   // Reverse Headlinght FL(f)
uint8_t gCV49_FC = 0b00000000;   // Function 1
uint8_t gCV50_FC = 0b00000000;   // Function 2
uint8_t gCV51_FC = 0b00000000;   // Function 3
uint8_t gCV52_FC = 0b00000000;   // Function 4
uint8_t gCV53_FC = 0b00000000;   // Function 5
uint8_t gCV54_FC = 0b00000000;   // Function 6
uint8_t gCV55_FC = 0b00000000;   // Function 7
uint8_t gCV56_FC = 0b00000000;   // Function 8
uint8_t gCV57_FC = 0b00000000;   // Function 9
uint8_t gCV58_FC = 0b00000000;   // Function 10
uint8_t gCV59_FC = 0b00000000;   // Function 11
uint8_t gCV60_FC = 0b00000000;   // Function 12

// 0x80 PTNB3
// 0x40 PTNB2
// 0x20 PTNB1
// 0x10 PTNB0
// 0x08 DIMCON
// 0x04 DIRCON
// 0x02 FORREV
// 0x01 ALWAYS
//                    +--------0:Db3
//                    |+-------0:Db2
//                    ||+------0:Db1
//                    |||+-----0:Db0 Event側 調光 (0000-1111) 16段階
//                    ||||+----0:Db3  
//                    |||||+---0:Db2   
//                    ||||||+--0:Db1
//                    |||||||+-0:Db0 Normal側 調光 (0000-1111) 16段階
//                    ||||||||
uint8_t gCV112_FC = 0b00000000;   // Forward Headlinght FL(f)
uint8_t gCV113_FC = 0b00000000;   // Reverse Headlinght FL(f)
uint8_t gCV114_FC = 0b00000000;   // Function 1
uint8_t gCV115_FC = 0b00000000;   // Function 2
uint8_t gCV116_FC = 0b00000000;   // Function 3
uint8_t gCV117_FC = 0b00000000;   // Function 4
uint8_t gCV118_FC = 0b00000000;   // Function 5

uint8_t gCV119_FC = 0b00000000;   // Function 6
uint8_t gCV120_FC = 0b00000000;   // Function 7
uint8_t gCV121_FC = 0b00000000;   // Function 8
uint8_t gCV122_FC = 0b00000000;   // Function 9
uint8_t gCV123_FC = 0b00000000;   // Function 10
uint8_t gCV124_FC = 0b00000000;   // Function 11
uint8_t gCV125_FC = 0b00000000;   // Function 12

//                    +--------0:
//                    |+-------0:
//                    ||+------0:
//                    |||+-----0:
//                    ||||+----0:Sb3
//                    |||||+---0:Sb2   
//                    ||||||+--0:Sb1
//                    |||||||+-0:Sb0 速度閾値 (0000-1111) 16段階　Threshold
//                    ||||||||
uint8_t gCV126_FC = 0b00000000;   // Forward Headlinght FL(f)
uint8_t gCV127_FC = 0b00000000;   // Reverse Headlinght FL(f)
uint8_t gCV128_FC = 0b00000000;   // Function 1
uint8_t gCV129_FC = 0b00000000;   // Function 2
uint8_t gCV130_FC = 0b00000000;   // Function 3
uint8_t gCV131_FC = 0b00000000;   // Function 4
uint8_t gCV132_FC = 0b00000000;   // Function 5
uint8_t gCV133_FC = 0b00000000;   // Function 6
uint8_t gCV134_FC = 0b00000000;   // Function 7
uint8_t gCV135_FC = 0b00000000;   // Function 8
uint8_t gCV136_FC = 0b00000000;   // Function 9
uint8_t gCV137_FC = 0b00000000;   // Function 10
uint8_t gCV138_FC = 0b00000000;   // Function 11
uint8_t gCV139_FC = 0b00000000;   // Function 12



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

//
// stateマシンを実行させるファンクッション
// b0:Head
// b1:Tail
// b2:Function 1
//      ：
// b13:Function 12
//
//uint16_t FunctionStateEna = 0b0000000000000011;
```

```cpp:define.h
#ifndef _DEFINE_H_
#define _DEFINE_H_


//各種設定、宣言

#define DECODER_ADDRESS 3
#define DCC_ACK_PIN 2   // 32 PD2 INT0  
#define AUX1 9          // 13 PB1 PWM_C OC1A
#define AUX2 10         // 14 PB2 PWM_D OC1B
#define AUX3 5          //  9 PD5 PWM_E OC0B
#define AUX4 6          // 10 PD6 PWM_F OSC1
//#define AUX5 A2         // 25 PC2
//#define AUX6 A3         // 26 PC3
//#define AUX7 A4         // 27 PC4
//#define AUX8 A5         // 28 PC5
#define AUX5 1         // 25 PC2
#define AUX6 2         // 26 PC3
#define AUX7 3         // 27 PC4
#define AUX8 4         // 28 PC5
#define Bi1 11          // 15 PB3 PWM_A OC2A
#define Bi2 3           //  1 PD3 PWM_B OC2B

#define PTNB3 0x80      //
#define PTNB2 0x40      //
#define PTNB1 0x20      //
#define PTNB0 0x10      //
#define DIMCON 0x08     // 0:Event調光無効 1:Event調光有効
#define DIRCON 0x04     // 0:Disable 1:enable (方向制御For/Rev)
#define FORREV 0x02     // 0:Forward 1:Reverse
#define ALWAYS 0x01     // 0:normal 1:常に点灯

#define FORWARD 1
#define REVERSE 0

#endif// _DEFINE_H_
```