
/**
* @file RespirationBelt.cpp
*
* @brief The file contains the sources for TUsb respiration belt object
**/


/*!
Header include
*/
#include "Plugin.h"


/*!
Standard constructor and destructor
*/
RespirationBelt::RespirationBelt()
{
  // Create a new TUsb COM controller
	m_pIMonCom = new IT_USBComPtr(__uuidof(Controller)); 

  // Launch update loop thread
  m_isConnected = false;
  exitRequested = false;
  comState = false;

  // Set refresh loop rate according to acquisition frequency
  int fps = static_cast<int> (1000.0f / 60.0f);
  loopThread = new boost::thread(boost::bind(&RespirationBelt::GoThread, this), boost::posix_time::millisec(fps));

  // Initialize class members
  SetChestExtension(0.0f);
  SetBatteryLevel(0.0f);
}

RespirationBelt::~RespirationBelt()
{
  // Stop update loop thread
  exitRequested = true;
  comState = false;
  if (loopThread != 0)
    loopThread->join();
  
  // Close connection to TUsb module
  Disconnect();
}


/*!
Getters and Setters
*/
double RespirationBelt::GetChestExtension()
{
  return m_chestExtension;
}

float RespirationBelt::GetBatteryLevel()
{
  return m_batteryLevel;
}

void RespirationBelt::SetChestExtension(double extensionPercent)
{
  m_chestExtension = extensionPercent;
}

void RespirationBelt::SetBatteryLevel(float batteryPercent)
{
  m_batteryLevel = batteryPercent;
}


/*!
Connection and Disconnection
*/
bool RespirationBelt::Connect(long comPort, long carryingFrequency)
{
  // Set COM port and connect to TUsb
  MMechostr(MSKDEBUG, "COM connection attempt on port [%d]\n", comPort);
	int ret = m_pIMonCom->setPortCom(comPort);
	if (ret == 1)
	{
		// Connection successful
		MMechostr(MSKDEBUG, "TUSB is now connected on port [%ld] \nNow searching for TSens...", comPort);

    // Set carryinq frequency for data acquisition
	  ret = m_pIMonCom->setCarryingWaveFrequency(carryingFrequency);

    // Create a one dimensional SafeArray of integers
    SAFEARRAY *pSA;
    SAFEARRAYBOUND aDim[1];
    aDim[0].lLbound = 0;
    aDim[0].cElements = 6;
    pSA = SafeArrayCreate(VT_I4, 1, aDim);

    // Scan all the sensors connected to the TUsb module
    long nbDetectedTSens = m_pIMonCom->scan(&pSA);
    MMechostr(MSKDEBUG, "%d T-Sens detected\n", nbDetectedTSens);
  	
    // Set up real-time data recording
    ret = m_pIMonCom->recConfig(1, 0, "");
    if (ret < 0)
    {
	    // Error launching data recording
	    MMechostr(MSKDEBUG, "TUSB didn't manage to configure the paramater for the record... Press RETURN to exit\n");
	    return false;
    }
    MMechostr(MSKDEBUG, "Record is ready to start... \n");

    // Retrieve battery level
    SetBatteryLevel(m_pIMonCom->getBattery(1));
    PostMessage(HScol, TUSB_BATTERY_LEVEL_CB, (int)this, (LPARAM)(GetBatteryLevel()));

    // Start data acquisition
    ret = m_pIMonCom->startRec();
    if (ret < 0)		
    {
	    // Error launching data recording
	    MMechostr(MSKDEBUG, "TUSB didn't manage to launch record... Press RETURN to exit\n");
	    return false;
    }
    MMechostr(MSKDEBUG, "Record has started!\n");

    // Send notification to Scol handle
    m_isConnected = true;
    PostMessage(HScol, TUSB_CONNECTED_CB, (int)this, (LPARAM)NULL);
    return true;
	}
	else
	{
		// Connection failed
		MMechostr(MSKDEBUG, "Connexion attempt failed! (error %d)\n", ret);
		return false;
	}
}

bool RespirationBelt::Disconnect()
{
  // Stop data acquisition
  int ret = m_pIMonCom->stopRec();
	if (ret < 0)
	{
		MMechostr(MSKDEBUG, "TUSB failed to stop recording...\n");
    return false;
	}
	MMechostr(MSKDEBUG, "Record has been stopped.\n");

  // Close COM port
  ret = m_pIMonCom->closePortCom();
  if (ret == -1)
  {
    MMechostr(MSKDEBUG, "Failed to close COM port...\n");
    return false;
  }
	MMechostr(MSKDEBUG, "COM port has been successfully closed.\n");
  m_isConnected = false;

  // Send notification to Scol handle
  PostMessage(HScol, TUSB_DISCONNECTED_CB, (int)this, (LPARAM)NULL);

  return true;
}

/*!
Handle new fixation data
*/
void RespirationBelt::ParseData()
{
  // Check if respiration belt is still connected
  if (m_pIMonCom->IsTSensConnected(1))
  {
    // Check if new data is available for TUsb module
    int nbData = m_pIMonCom->isDataRTAvailable(1);
    if (nbData > 0)
    {
      // Create 1D one and two dimensional arrays for data acquisition
      SAFEARRAY *TStime, *TSdata;
      SAFEARRAYBOUND timeDim[1], dataDim[2];
      timeDim[0].lLbound = dataDim[0].lLbound = dataDim[1].lLbound = 0;
      timeDim[0].cElements = dataDim[0].cElements = dataDim[1].cElements = nbData;
      TStime = SafeArrayCreate(VT_R8, 1, timeDim);
      TSdata = SafeArrayCreate(VT_R8, 2, dataDim);

      // Get new TUsb module data, including time stamp
      m_pIMonCom->getDataRT(1, &TSdata, &TStime, nbData);
      double beltExtension = 0.0f;
      long ix[2];

      // Create a data structure to retrieve new values of belt extension
      BeltData *beltData = new BeltData();
      for (int j=0; j<=nbData-1; j++)
      {
        ix[0] = 0;
        ix[1] = j;

        // Get current belt extension value
        SafeArrayGetElement(TSdata, ix, (void*)&beltExtension);

        // Add new data to the list
        beltData->AddData(static_cast<float>(beltExtension));
      }

      // Send message to Scol handle
      PostMessage(HScol, TUSB_NEW_DATA_CB, (int)this, (LPARAM)beltData);
    }
  }
}


/*!
Handle Boost threading
*/
void RespirationBelt::GoThread()
{
  while(!exitRequested)
  {
    if (!m_isConnected)
    {
      // Enumerate the list of available COM ports
      std::list<unsigned int> lport = LSerie::enumAvailablePorts();
      std::list<unsigned int>::iterator it = lport.begin();
      while (!comState && (it != lport.end()))
      {
        // Establish a safe COM connection
        if (Connect(*it, CARRYING_FREQ))    // NOTE: The carrying frequency mustn't be changed, it is specific to the TUsb device
          comState = true;
        it++;
      }
    }
    else
    {
      // Lock during operation
      boost::mutex::scoped_lock lockNewData(mutexNewData);

      // Retrieve new data
      ParseData();
    }
  }
}
