//------------------------------------------------------------------
//  遮断周波数可変 IIR フィルタ（LPF, HPF）
//      DA 出力はアップサンプリング使用
//      フィルタの係数の計算をマイコン側でも行うタイプ
//
//  PC 側のプログラム： 遮断周波数可変IIRフィルタ.exe
//
//  2023/01/17, Copyright (c) 2023 MIKAMI, Naoki
//------------------------------------------------------------------

#include "MultirateLiPh.hpp"    // DA でアップサンプリング
#include "SerialRxTxIntr.hpp"
#include "IirVariable.hpp"
using namespace Mikami;

const float FS_ = 44.1f;    // 入力の標本化周波数： 44.1 kHz
MultirateLiPh myAdDa_(FS_); // 出力標本化周波数を４倍にするオブジェクト

// 縦続形 IIR フィルタによる可変フィルタのオブジェクト
//      次数： 10 次
//      最初に設計されるフィルタ：遮断周波数 1 kHz の LPF
VariableIir filter_(10, FS_*1000, 1000.0f, BilinearDesign::LPF);

// LPF/HPF の信号処理
void AdcIsr()
{
    float xn = myAdDa_.Input();     // 入力
    float yn = filter_.Execute(xn); // IIR フィルタの実行
    myAdDa_.Output(yn);             // 出力
}

int main()
{   
    SerialRxTxIntr com;                  // PC との通信用
    NVIC_SetPriority(USART2_IRQn, 2);   // シリアルポートの割り込み順位設定

    myAdDa_.Start(&AdcIsr);     // 標本化を開始する
    BilinearDesign::Type typeOld = BilinearDesign::LPF;
    while (com.WaitGetBuffer() != "VrFc") {}
    com.TxString("ACK\n");      // "ACK" を送り返す

    // PC からの指令に対応する処理
    while (true)
    {
        string str = com.WaitGetBuffer();   // PC からの指令を取得
        if (str == "ACTIVE")
        {
            filter_.Clear();
            filter_.Validate();                         // フィルタ処理有効
        }
        else if (str == "THROUGH") filter_.Invalidate();// フィルタ処理無効
        else    // 上記以外はフィルタの遮断周波数の情報が送信される
        {
            BilinearDesign::Type type;
            if (str.substr(0, 1) == "L") type = BilinearDesign::LPF;
            else                         type = BilinearDesign::HPF;

            // 先頭の１文字を除いた部分が遮断周波数に対応する文字列
            float fc = atoi(str.substr(1).c_str()); // 遮断周波数
            filter_.SetParameters(fc, type);

            // LPF と HPF が切り替わった場合フィルタの単位遅延素子をクリア
            if (type != typeOld) filter_.Clear();
            typeOld = type;
        }
    }
}
