/******************************************************************************
*
* Windows Example:
*    StaticAO.cpp
*
* Example Category:
*    AO
*
* Description:
*    This example demonstrates how to use Static AO voltage function.
*
* Instructions for Running:
*    1  Set the 'deviceDescription' for opening the device. 
*	  2  Set the 'profilePath' to save the profile path of being initialized device. 
*    3  Set the 'channelStart' as the first channel for analog data output.
*    4  Set the 'channelCount' to decide how many sequential channels to output analog data.
*
* I/O Connections Overview:
*    Please refer to your hardware reference manual.
*
******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <math.h>
#include "../inc/compatibility.h"
#include "../inc/bdaqctrl.h"
#include "StaticAO.h"
using namespace std;
using namespace Automation::BDaq;
//-----------------------------------------------------------------------------------
// Configure the following parameters before running the demo
//-----------------------------------------------------------------------------------
#define     ONE_WAVE_POINT_COUNT  512 //define how many data to makeup a waveform period.
 
#define     deviceDescription  L"PCI-1724,BID#0" // 设备描述
const wchar_t* profilePath = L"../../profile/PCI-1724.xml"; // 配置文件路径
int32       channelStart = 0; // 输出数据的起始通道
int32       channelCount = 1; // 输出数据的通道数量

//function GenerateWaveform: generate one waveform for each selected analog data output channel 
ErrorCode GenerateWaveform( InstantAoCtrl * instantAoCtrl,int32 channelStart,int32 channelCount,  double * waveBuffer, int32 SamplesCount,WaveStyle style);
 
inline void waitAnyKey()
{
   do{SLEEP(1);} while(!kbhit()); // 等待任意键
} 
//----------代码作用：生成单通道波形数据----------
//----------输入参数：instantAoCtrl：InstantAoCtrl类实例；channelStart：输出数据的起始通道；channelCount：输出数据的通道数量；waveBuffer：输出波形数据缓冲区；SamplesCount：波形数据点数；style：波形类型枚举----------
//----------输出参数：返回值：成功返回Success，失败返回错误码----------



void StaticAO::AO_1724::Static_AO(int argc, StaticAO_data* argv)
{
   ErrorCode ret = Success;
   // Step 1: Create a 'InstantAoCtrl' for Static AO function.
   InstantAoCtrl * instantAoCtrl = InstantAoCtrl::Create();
   do
   {
      // Step 2: Select a device by device number or device description and specify the access mode.
      // in this example we use ModeWrite mode so that we can fully control the device, including configuring, sampling, etc.
      DeviceInformation devInfo(deviceDescription);
      ret = instantAoCtrl->setSelectedDevice(devInfo); // 选择设备
      CHK_RESULT(ret);
      ret = instantAoCtrl->LoadProfile(profilePath); // 加载配置文件以初始化设备
      CHK_RESULT(ret);
 
      // Step 3: Output data 
      // Generate waveform data
      double *waveform = (double*)malloc( channelCount*ONE_WAVE_POINT_COUNT*sizeof(double)); // 分配内存用于波形数据
      if( NULL  == waveform )
      {
         printf( "Insufficient memory available\n" ); // 检查内存分配情况
         break;
      }
      ret = GenerateWaveform( instantAoCtrl,channelStart,channelCount, waveform,channelCount*ONE_WAVE_POINT_COUNT,argv->style,argv->current); // 生成波形
      CHK_RESULT(ret);
 
      printf("\n Outputting data...  any key to quit!\n"); // 输出数据提示
      bool enforced = false; // 强制退出标志
      do 
      {
         for( int32 i = 0; i < ONE_WAVE_POINT_COUNT; i++ ) 
         { 
            ret = instantAoCtrl->Write(channelStart, channelCount, &waveform[channelCount*i]); // 写入数据
            CHK_RESULT(ret);
            SLEEP(1); // 延时
            cout << "当前输出数据点数：" << i << endl; // 输出提示信息
            if(kbhit())
            {
               printf("\n Static AO is over compulsorily"); // 强制结束提示
               enforced = true;
               break;
            }
         } 
      } while (false);
      free(waveform); // 释放波形数据内存
      if (!enforced)
      {
         printf("\n Static AO is over, press any key to quit!\n"); // 正常结束提示
      }
   }while(false);
    
 // Step 4: Close device and release any allocated resource.
 instantAoCtrl->Dispose(); // 关闭设备并释放资源
 
 // If something wrong in this execution, print the error code on screen for tracking.
   if(BioFailed(ret)) // 错误处理
   {
      wchar_t enumString[256];
      AdxEnumToString(L"ErrorCode", (int32)ret, 256, enumString); // 获取错误信息
      printf("Some error occurred. And the last error code is 0x%X. [%ls]\n", ret, enumString);
      waitAnyKey(); // 等待任意键退出
   }
  
}
 
 
ErrorCode GenerateWaveform( InstantAoCtrl * instantAoCtrl, int32 channelStart,int32 channelCount,double * waveBuffer,int32 SamplesCount,WaveStyle style,double referenceValue)
{
   ErrorCode ret = Success; // 初始化返回状态
   int32    channel = 0; // 当前通道索引
   int32    channelCountMax = 0; // 最大通道数
   int32    oneWaveSamplesCount = SamplesCount/channelCount; // 每通道波形样本数量
   int32    i = 0; // 循环索引
 
   MathInterval  ranges[64] ; // 通道值范围
   ValueRange valRange; // 存储通道值范围
   channelCountMax =  instantAoCtrl->getFeatures()->getChannelCountMax(); // 获取设备最大通道数
   for(i = 0;i < channelCountMax ;i++ )
   {
      valRange = instantAoCtrl->getChannels()->getItem(i).getValueRange(); // 获取当前通道的值范围
      if ( V_ExternalRefBipolar == valRange || valRange == V_ExternalRefUnipolar ) // 如果是外部参考
      {
   if (instantAoCtrl->getFeatures()->getExternalRefAntiPolar())
   {
   // 参考值
 
   if (valRange == V_ExternalRefBipolar)
   {
    referenceValue = instantAoCtrl->getChannels()->getItem(i).getExtRefBipolar(); // 获取双极性参考值
    if (referenceValue >= 0) {
     ranges[i].Max = referenceValue; // 设置最大值
     ranges[i].Min = 0 - referenceValue; // 设置最小值
    } else {
     ranges[i].Max = 0 - referenceValue; 
     ranges[i].Min = referenceValue;
    }
   }
   else
   {
    referenceValue = instantAoCtrl->getChannels()->getItem(i).getExtRefUnipolar(); // 获取单极性参考值
    if (referenceValue >= 0) {
     ranges[i].Max = 0;
     ranges[i].Min = 0 - referenceValue;
    } else {
     ranges[i].Max = 0 - referenceValue; 
     ranges[i].Min = 0;
    }
   }	
   }
   else
   {
   double referenceValue; // 参考值
 
   if (valRange == V_ExternalRefBipolar)
   {
    referenceValue = instantAoCtrl->getChannels()->getItem(i).getExtRefBipolar(); // 获取双极性参考值
    if (referenceValue >= 0) {
     ranges[i].Max = referenceValue; // 设置最大值
     ranges[i].Min = 0 - referenceValue; // 设置最小值
    } else {
     ranges[i].Max = 0 - referenceValue; 
     ranges[i].Min = referenceValue;
    }
   }
   else
   {
    referenceValue = instantAoCtrl->getChannels()->getItem(i).getExtRefUnipolar(); // 获取单极性参考值
    if (referenceValue >= 0) {
     ranges[i].Max = referenceValue; // 设置最大值
     ranges[i].Min = 0;
    } else {
     ranges[i].Max = 0; 
     ranges[i].Min = referenceValue;
    }
   }	
   }
      } 
   else {
         ret = AdxGetValueRangeInformation( valRange,0,NULL,&ranges[i],NULL); // 获取值范围信息
         if(BioFailed(ret))
         {
            return ret; // 返回错误状态
         }
      }
   }
 
   //generate waveform data and put them into the buffer which the parameter 'waveBuffer' give in, the Amplitude these waveform
   for(i = 0; i < oneWaveSamplesCount; i++ ) 
   { 
      for( int32 j = channelStart; j < channelStart+channelCount; j++ )
      {
         //pay attention to channel rollback(when startChannel+channelCount>chNumberMax+1)
         channel = j%channelCountMax; // 处理通道回卷
    
   double amplitude = (ranges[channel].Max - ranges[channel].Min) / 2; // 幅度计算
   double offset = (ranges[channel].Max + ranges[channel].Min) / 2; // 偏移计算
 
         switch ( style) // 根据波形类型生成波形数据
         {
         case Sine:
            *waveBuffer++ = amplitude*(sin((double)i*2.0*( 3.14159 )/oneWaveSamplesCount )) + offset; 
            break;
         case  Sawtooth:
            if ((i >= 0) && (i < (oneWaveSamplesCount / 4.0)))
            {
               *waveBuffer++ =  amplitude*( i/(oneWaveSamplesCount/4.0)) + offset;
            }
            else
            {
               if ((i >= (oneWaveSamplesCount / 4.0)) && (i < 3 * (oneWaveSamplesCount/4.0)))
               {
                  *waveBuffer++ = amplitude* ((2.0*(oneWaveSamplesCount/4.0)-i)/(oneWaveSamplesCount/4.0)) + offset;
               }
               else
               { 
                  *waveBuffer++ = amplitude* ((i-oneWaveSamplesCount)/(oneWaveSamplesCount/4.0)) + offset; 
               }
            }
            break;
         case  Square:
            if ((i >= 0) && (i < (oneWaveSamplesCount / 2)))
            {
               *waveBuffer++ = amplitude * 1 + offset;
            }
            else
            {
               *waveBuffer++ = amplitude * (-1) + offset;
            }
            break;
         default:
            printf("invalid wave style,generate waveform error !"); // 无效波形类型提示
            ret = ErrorUndefined; // 返回未定义错误
         }
      } 
   }
   return ret; // 返回状态
};
