2017年7月17日月曜日

Arduinoアプリケーション用基本クラス

Arduino用の実験アプリをあれこれ作っているわけですが、アプリを作る場合、最低限必要な機能があるのでアプリケーション用基本クラスを作成しました。今後公開するアプリはみなこのクラスの派生クラスとして実装しますので、とりあえず公開しておきます。
時間を見てgithubに公開しようと思いますがそれまでの仮です^^;

KyaDefine.h

#ifndef _KyaDefine_h_
#define _KyaDefine_h_
/**
 * 定数定義
 *
 * filename:  KyaDefine.h
 *
 * @package
 * @version   1.0.0
 * @copyright Copyright (C) 2017 Yoshio Kiya
 * @date      2017-05-16
 * @author    木屋 善夫
 */
#define UINT unsigned int

// Arduino15\packages\digistump\hardware\avr\1.6.7\cores\tiny/Print.h で使っている!
//#ifndef BYTE
//  #define BYTE unsigned char
//#endif

#ifndef WORD
  #define WORD unsigned short
#endif

#ifndef DWORD
  #define DWORD unsigned long
#endif

#ifndef PCSTR
  #define PCSTR const char*
#endif

// 要素数を返す
#define numberof( a ) ((sizeof a) / (sizeof a[0]))

#define TRUE 1
#define FALSE 0

#if !defined( D0 ) && defined( ARDUINO_AVR_UNO )
  enum {
    D0  =  0,
    D1  =  1,
    D2  =  2,
    D3  =  3,
    D4  =  4,
    D5  =  5,
    D6  =  6,
    D7  =  7,
    D8  =  8,
    D9  =  9,
    D10 = 10,
    D11 = 11,
    D12 = 12,
    D13 = 13,
  };
#endif

#endif

KyaApp.h

#ifndef _KyaApp_h_
#define _KyaApp_h_
/**
 * アプリケーションの基本クラス
 *
 * filename:  KyaApp.h
 *
 * @package
 * @version   1.0.0
 * @copyright Copyright (C) 2017 Yoshio Kiya
 * @date      2017-05-16
 * @author    木屋 善夫
 */
#include
#ifdef KYA_TIMER_INTERVAL
  #ifndef ESP8266
    #include
  #else
    // ミリ秒をクロック数に換算 (@80MHz)
    #define MSEC2CLOCK(ms)  (ms * 80000L)
  #endif
#endif

#include

#ifdef KYA_DEBUG
#define TRACE KyaApp::trace( __FUNCTION__, __FILE__, __LINE__ );
#else
#define TRACE
#endif

// 3Dベクター
template
class KyaVec3 {
public:
  TYPE x;
  TYPE y;
  TYPE z;
};

// 時刻
typedef union KyaTime {
  DWORD val;
  struct {
    uint8_t s;
    uint8_t m;
    WORD h;
  };
};

//printf で小数を扱うためのマクロ
// ex. printf( "%d.%02d", printfFloat( val, 100 ) );
// 小数点以下2桁が表示される
#define printfFloat( v, c ) (int)v, abs( (int)((v - (int)v) * c) )

//// イベントハンドル
//@@ 関数ポインターではなくメンバー関数へのポインターにしなければならない
//template
//class KyaHandle
//{
//public:
//  void *mFunc( TYPE );
//  int mMilli;
//  TYPE mArg;
//
//  KyaHandle( void *func( TYPE ), int delay, TYPE arg ) {
//    mFunc = func;
//    mMilli = millis() + delay;
//    mArg = arg;
//  }
//}

class KyaApp
{
private:

protected:

public:
  static KyaApp* app;
  static char gPfb[256];

  /**
   * 構築
   *
   * @access public
   */
  KyaApp( ) {
    app = this;
  };

  /**
   * 設定
   *
   * @access public
   */
  virtual void onSetup( ) {
    TRACE
#ifdef KYA_TIMER_INTERVAL
  #ifndef ESP8266
    MsTimer2::set( KYA_TIMER_INTERVAL, timerEntry );  // 割り込みハンドラの設定
    MsTimer2::start();                                // タイマー割り込み開始
    Serial.println( "MsTimer2::start()" );
  #else
    // タイマ割り込みの設定
    noInterrupts();

    timer0_isr_init();

    // ハンドラのエントリを設定
    timer0_attachInterrupt( timerEntry );

    // 次回の割り込みが発生するまでの時間を設定
    timer0_write(ESP.getCycleCount() + MSEC2CLOCK(KYA_TIMER_INTERVAL) ); // 10msec

    interrupts();
  #endif
#endif  // KYA_TIMER_INTERVAL
  }

  /**
   * ループの中身
   *
   * @access public
   */
  virtual void onLoop() {
  }

  /**
   * タイマーハンドラ
   *
   * @access public
   */
  virtual void onTimer( ) {
  }

  /**
   * ミリ秒を 時分秒でシリアルに出力
   *
   * @param  DWORD ms ミリ秒
   * @param  const char* suffix 時分秒のあとに付ける文字列
   */
  void printMillis( DWORD ms, const char* suffix = NULL );

#ifdef KYA_TIMER_INTERVAL
  /**
   * 17ms毎にここが呼び出される
   */
  static void timerEntry( ) {
  #ifdef ESP8266
    // 次回の割り込みが発生するまでの時間を設定
    timer0_write(ESP.getCycleCount() + MSEC2CLOCK(KYA_TIMER_INTERVAL) ); // 10msec
  #endif

    // 割り込み処理ハンドラを呼び出す
    if ( KyaApp::app ) {
      KyaApp::app->onTimer( );
    }
  }
#endif  // KYA_TIMER_INTERVAL

  /**
   * LED 点滅
   *
   * @access public
   * @param
   */
//  static void blinkLED( UINT port, UINT blight, UINT usec, UINT count = 1, UINT duty = 128 );
  static void blinkLED( uint8_t port, uint8_t usec, uint8_t count = 1, uint8_t blight = 255, uint8_t duty = 128 );

  /**
   * LED 点滅
   *
   * @param  uint8_t port ピン番号
   * @param  WORD counter カウンター
   * @param  WORD high HIGH にする回数
   * @param  WORD low  LOW にする回数
   * @return WORD カウンター
   */
  static WORD blinkLED2( uint8_t port, WORD counter, WORD high, WORD low );

  /**
   * LED 点滅
   *
   * @param  uint8_t port ピン番号
   * @param  int high HIGH の時間(msec)
   * @param  int low  LOW  の時間(msec)
   */
  static void blinkLED3( uint8_t port, int high, int low );

  /**
   * LED 点滅
   *
   * @param  uint8_t port  ポート
   * @param  WORD pos   現在位置
   * @param  WORD speed 速度
   * @return 次の位置
   */
  static WORD winkLED( uint8_t port, WORD pos, WORD speed = 1 );

  /**
   * 書式付きコンソール出力
   *
   * @param  PCSTR format 書式文字列
   */
  static void printf( PCSTR format, ... );

  static void puts( PCSTR str ) {
    Serial.println( str );
  }

  static void putstr( PCSTR str ) {
    Serial.print( str );
  }

  /**
   * ミリ秒から時分秒を取得
   *
   * @access public
   * @param  unsigned long msec ミリ秒
   * @return KyaTime 時分秒
   */
  KyaTime msecToTime( unsigned long msec );

  /**
   * トレース
   *
   * @param
   * @return
   */
  static void trace( PCSTR func, PCSTR file, int line );
};

#endif

KyaApp.cpp

/**
 * アプリケーションの基本クラス
 *
 * filename:  KyaApp.cpp
 *
 * @package
 * @version   1.0.0
 * @copyright Copyright (C) 2017 Yoshio Kiya
 * @date      2017-05-16
 * @author    木屋 善夫
 */
#include "KyaApp.h"

KyaApp* KyaApp::app = NULL;
char KyaApp::gPfb[256];

/**
 * ミリ秒を 時分秒でシリアルに出力
 *
 * @param  DWORD ms ミリ秒
 * @param  const char* suffix 時分秒のあとに付ける文字列
 */
void KyaApp::printMillis( DWORD ms, const char* suffix ) {
  // 起動してからの時間を表示
  int h, m, s;
  s = ms / 1000;
  if ( s >= 60 ) {
    m = s / 60;
    s = s % 60;
    if ( m >= 60 ) {
      h = m / 60;
      m = m % 60;
    } else {
      h = 0;
    }
  } else {
    h = 0;
    m = 0;
  }

  char buff[255];
  sprintf( buff, "%02d:%02d:%02d", h, m, s );
  Serial.print( buff );

  if ( suffix ) {
    Serial.print( suffix );
  }
}

/**
 * LED 点滅
 *
 * @param
 * @return
 */
//void KyaApp::blinkLED( UINT port, UINT blight, UINT usec, UINT count, UINT duty )
void KyaApp::blinkLED( uint8_t port, uint8_t usec, uint8_t count, uint8_t blight, uint8_t duty )
{
  while ( (count --) > 0 ) {
    // on
    if ( blight < 255 ) {
      analogWrite( port, blight );
    } else {
      digitalWrite( port, HIGH );
    }
    if ( duty != 0 ) {
      delay( (usec * duty) >> 8 );
    }

    // off
    digitalWrite( port, LOW );
    if ( duty != 255 ) {
      delay( (usec * (255 - duty)) >> 8 );
    }
  }
}

/**
 * LED 点滅
 *
 * @param  uint8_t port ピン番号
 * @param  WORD counter カウンター
 * @param  WORD high HIGH にする回数
 * @param  WORD low  LOW にする回数
 * @return WORD カウンター
 */
WORD KyaApp::blinkLED2( uint8_t port, WORD counter, WORD high, WORD low ) {
  WORD t = (counter ++) % (high + low);

  if ( t < high ) {
    digitalWrite( port, HIGH );
  } else {
    digitalWrite( port, LOW );
  }

  return counter;
}

/**
 * LED 点滅
 *
 * @param  uint8_t port ピン番号
 * @param  int high HIGH の時間(msec)
 * @param  int low  LOW  の時間(msec)
 */
void KyaApp::blinkLED3( uint8_t port, int high, int low ) {
  int t = millis( ) % (high + low);
  if ( t < high ) {
    digitalWrite( port, HIGH );
  } else {
    digitalWrite( port, LOW  );
  }
}


/**
 * LED 点滅
 *
 * @param  uint8_t port  ポート
 * @param  WORD pos   現在位置
 * @param  WORD speed 速度
 * @return 次の位置
 */
WORD KyaApp::winkLED( uint8_t port, WORD pos, WORD speed ) {
  // LEDの点滅
  uint8_t b;
  if ( !(pos & 0x100) ) {
    // < 0x100 is rise
    b = (uint8_t)pos;
  } else {
    // >= 0x100 is set
    b = 0xFF - (uint8_t)pos;
  }
  analogWrite( port, b );

  return pos + speed;
}

/**
 * 書式付きコンソール出力
 *
 * @param  PCSTR format 書式文字列
 */
void KyaApp::printf( PCSTR format, ... ) {
  char buff[256];
  va_list arg;

  va_start( arg, format );
  vsnprintf( buff, sizeof( buff ) - 1, format, arg );
  va_end( arg );

  // 改行で分割しながら描画
  char* p = buff;
  char* f;
  while ( (f = strchr( p, '\n' )) != NULL ) {
    // 終端文字を設定
    *f = 0;
    // 改行付きで主力
    Serial.println( p );
    // 見つけた改行文字の次
    p = f + 1;
  }

  // 文字列が残っていたら主力する
  if ( *p ) {
    Serial.print( buff );
  }
}

/**
 * ミリ秒から時分秒を取得
 *
 * @access public
 * @param  unsigned long msec ミリ秒
 * @return KyaTime 時分秒
 */
KyaTime KyaApp::msecToTime( unsigned long msec )
{
  KyaTime res;

  // 秒単位に変換
  msec = msec / 1000;

  // 秒数を抽出
  res.s = (uint8_t)(msec % 60);

  // 分単位に変換
  msec = msec / 60;

  // 分数を算出
  res.m = (uint8_t)(msec % 60);

  // 時単位に変換
  msec = msec / 60;

  // 時間数を取得
  res.h = (WORD)msec;

  return res;
}


/**
 * トレース
 *
 * @param
 * @return
 */
void KyaApp::trace( PCSTR func, PCSTR file, int line ) {
  Serial.print( func );
  Serial.print( "() " );
  Serial.print( file );
  Serial.print( "(" );
  Serial.print( line );
  Serial.print( ")" );
  Serial.println( );
}

/**
 * 設定エントリ
 */
void setup() {
  Serial.begin( 115200 );
  Serial.println( "" );

  if ( KyaApp::app != NULL ) {
    KyaApp::app->onSetup( );
  } else {
    Serial.println( "KyaApp::app == NULL." );
  }
}

/**
 * ループエントリ
 */
void loop() {
  if ( KyaApp::app != NULL ) {
    KyaApp::app->onLoop( );
  } else {
    Serial.println( "KyaApp::app == NULL." );
    delay( 60 * 1000 );
  }
}

0 件のコメント: