2013/06/27

C++ Heart rate variability 8Z11 source code analysis (分析接收心律源碼)

最近實驗室又採購一台HRV(Heart rate variability)的裝置,拿到原始碼快速分析一下啦!
這樣暑假又可以忙推甄的事情,源碼部份有DelphiC++,那當然先看最愛得C++ XDDD

源碼看似是C#.Net,實際上是『Managed Extensions for C++』,有興趣朋友可以點擊看一下



這個程式主要透過兩個執行緒再去跑,透過readThread去接收資料,檔案存在data.bin

Hardware是由某間公司生產?所以Protocol都是他們自己設計的,這個源碼也是該公司提供,還重金聘請...XDDDDDDD


就得照著該公司的規範,百思不得其解是因為列舉就可以解決的事情,卻要設計成好幾個十六進位才能使用,好奇?

static array<Byte>^ TryDetect = {0x00, 0x00, 0x00};
static array<Byte>^ setupRFDB = {0x0b, 0x08, 0xff, 0x00, 0x00};
static array<Byte>^ setupXMIT = {0x07, 0x80, 0x07, 0x01, 0xff, 0xff, 0x00, 0x14, 0x21};
static array<Byte>^ StpDetect = {0x22, 0x22, 0x22};

先設定_serialPort的資訊,一樣要照該公司的規範去設定
        // Set the appropriate properties.
        _serialPort->PortName  = SetPortName(_serialPort->PortName);
        _serialPort->BaudRate  = 250000;
        _serialPort->Parity    = Parity::None;
        _serialPort->DataBits  = 8;
        _serialPort->StopBits  = StopBits::One;
        _serialPort->Handshake = Handshake::None;

        // Set the read/write timeouts
        _serialPort->ReadTimeout  = 500;
        _serialPort->WriteTimeout = 500;

接著去選擇COM Port
_serialPort->PortName  = SetPortName(_serialPort->PortName);


接著Open _serialPort並且判斷是否成功開啟,開啟失敗就終止程式
if (_serialPort->IsOpen == true) {
         Console::WriteLine("serialPort opened successfully!");
         _continue = true;
        }else {
         Console::WriteLine("serialPort opened failed!");
         message = Console::ReadLine();
         _serialPort->Close();
         fs->Close();
         return;
}

就會開始持續讀取資料
readThread->Start();

除非使用者輸入quit,否則會持續運作直到沒電
while (_continue){
     message = Console::ReadLine();

     if (stringComparer->Equals("quit", message)){
                _continue = false;
     }
}
整體程式碼如下

#using <System.dll>

using namespace System;
using namespace System::IO;
using namespace System::IO::Ports;
using namespace System::Threading;

public ref class PortChat
{
private:
    static bool _continue;
    static SerialPort^ _serialPort;
    static FileStream^ fs = gcnew FileStream("data.bin", FileMode::Create);
    static BinaryWriter^ w = gcnew BinaryWriter(fs);
    static Byte onebyte;
    static array<Byte>^ TryDetect = {0x00, 0x00, 0x00};
    static array<Byte>^ setupRFDB = {0x0b, 0x08, 0xff, 0x00, 0x00};
    static array<Byte>^ setupXMIT = {0x07, 0x80, 0x07, 0x01, 0xff, 0xff, 0x00, 0x14, 0x21};
    static array<Byte>^ StpDetect = {0x22, 0x22, 0x22};

public:
    static void Main()
    {
        String^ message;
        StringComparer^ stringComparer = StringComparer::OrdinalIgnoreCase;
        Thread^ readThread = gcnew Thread(gcnew ThreadStart(PortChat::Read));

        // Create a new SerialPort object with default settings.
        _serialPort = gcnew SerialPort();

        // Set the appropriate properties.
        _serialPort->PortName  = SetPortName(_serialPort->PortName);
        _serialPort->BaudRate  = 250000;
        _serialPort->Parity    = Parity::None;
        _serialPort->DataBits  = 8;
        _serialPort->StopBits  = StopBits::One;
        _serialPort->Handshake = Handshake::None;

        // Set the read/write timeouts
        _serialPort->ReadTimeout  = 500;
        _serialPort->WriteTimeout = 500;

 try{
  _serialPort->Open();
        }catch (IOException ^) {
         Console::WriteLine("serialPort opened failed!");
         message = Console::ReadLine();
                fs->Close();
         return;
        }

        if (_serialPort->IsOpen == true) {
         Console::WriteLine("serialPort opened successfully!");
         _continue = true;
        }
        else {
         Console::WriteLine("serialPort opened failed!");
         message = Console::ReadLine();
         _serialPort->Close();
         fs->Close();
         return;
        }

        readThread->Start();

        Console::WriteLine("Type quit to exit");
        Console::WriteLine("Press Enter to Start to Receive...");
        message = Console::ReadLine();

        _serialPort->RtsEnable = true;
        Thread::Sleep(1);
        _serialPort->RtsEnable = false;
        Thread::Sleep(500);

        _serialPort->Write(TryDetect, 0, 1);
        _serialPort->Write(TryDetect, 0, 1);

        _serialPort->Write(setupRFDB, 0, setupRFDB->Length);
        Thread::Sleep(10);
        _serialPort->Write(setupXMIT, 0, setupXMIT->Length);

        while (_continue)
        {
            message = Console::ReadLine();

            if (stringComparer->Equals("quit", message))
            {
                _continue = false;
            }
        }

     _serialPort->Write(TryDetect, 0, 1);
     _serialPort->Write(TryDetect, 0, 1);
     _serialPort->Write(TryDetect, 0, 1);

     _serialPort->Write(StpDetect, 0, 1);
     _serialPort->Write(StpDetect, 0, 1);
     _serialPort->Write(StpDetect, 0, 1);

        readThread->Join();
        _serialPort->Close();
        fs->Close();
    }

    static void Read()
    {
        while (_continue)
        {
         try{
                int count = _serialPort->BytesToRead;
                if (count > 0) {
                    array<Byte>^ Buffer = gcnew array<Byte>(count);
                    _serialPort->Read(Buffer, 0, count);

                    Console::WriteLine(L"\n{0} bytes received:", count);

                    for (int i=0; i<count; i++) {
                            w->Write(Buffer[i]);
                            Console::Write(L"{0} ", Buffer[i].ToString(L"X"));
                        }
                    }
            } catch (TimeoutException ^) {  }
        }
    }

    static String^ SetPortName(String^ defaultPortName)
    {
        String^ portName;

        Console::WriteLine("Available Ports:");
        for each (String^ s in SerialPort::GetPortNames())
        {
            Console::WriteLine("   {0}", s);
        }

        Console::Write("COM port: ");
        portName = Console::ReadLine();

        if (portName == "")
        {
            portName = defaultPortName;
        }
        return portName;
    }
};

int main()
{
    PortChat::Main();
}


執行畫面喔…省了
看起來直接寫在C#.Net或是WPF就好了吧?
Delphi的源碼想到在分析,差異不大


參考資料:
http://msdn.microsoft.com/zh-tw/library/system.io.ports.serialport.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1
http://en.wikipedia.org/wiki/Heart_rate_variability
http://www.dotblogs.com.tw/billchung/archive/2012/01/04/64319.aspx