裡面包含設定、量測、互動設計的部份。程式設計上,也有許多地方使用條件編譯,但是其實,在主程式的地方就將Ca210sim設定成debug版,Ca210real設定成release版。以免發佈時,還是模擬器的程式碼,量出一堆假的值。
CA-SDK本身,其實是使用Design Pattern的組合模式(Composite pattern)將CA-SDK做一個巧妙的設計,符合每一種可能的需求,而身為一個SDK應用開發,除了必須了解SDK的功能之外,還要了解如何將複雜的SDK包裝成適合自己需求的介面,降低複雜度,方便未來程式碼的維護和擴充速度。
Ca210real.h
#ifndef CA210REAL_H
#define CA210REAL_H
#include "CA210.h"
#include "ca200srvr.h"
#include "Bullet.h"
//單獨控制CA-210模組是不是要進入 DEBUG模式
//#define _CA210DEBUG _DEBUG
class Ca210real : public Ca210
{
ICa200 *m_pICa200;
ICa *m_pICa;
IProbe *m_pIProbe;
IMemory *m_pIMemory;
IProbeInfo *m_pIProbeInfo;
CaState m_caState;
CaState m_caStateTemp;
CString str;
CString ImpsbStr;
void MsgFrmt(CException* e, const CString&, const CString&);
void MsgFrmt(const CString&);
public:
Ca210real();
virtual ~Ca210real();
public:
const CaState CalZero();
const CaState Measure();
void LinkMemory();
const MsrAiState MsrAI(const float& MsrDeviation = 0.645);//any constant value
void SetOnline(const BOOL& b = TRUE);
const BOOL isOnline() const
{ return m_caState == CA_Offline ? FALSE : TRUE; };
const CString GetLcmSize();
const CString GetChData();// const;
const Bullet GetMsrData();
//for setup Dialog Value
const float GetRangeColor1() const;
const float GetRangeColor2() const;
const float GetRangeFAM() const;
void SetChId(const LPCTSTR& Id) { m_pIMemory->SetChannelID(Id); };
const CString GetChId() const { return m_pIMemory->GetChannelID(); };
const CString GetChId(const long& No) const { m_pIMemory->SetChannelNO(No); return m_pIMemory->GetChannelID(); };
void SetChNo(const long &No) { m_pIMemory->SetChannelNO(No); };
const long GetChNo() const { return m_pIMemory->GetChannelNO(); };
const CString GetChStrNo() /*const*/ { str.Format("%ld", m_pIMemory->GetChannelNO()); return str; };
const CString GetProb() const { return m_pIProbe->GetSerialNO(); };
const CString GetDeviceType() const { return m_pICa->GetCAType(); };
const CString GetCaVersion() const { return m_pICa->GetCAVersion(); };
const CString GetRefProbe() const;
const CString GetCalProbe() const;
const CString GetCalMode() const;
const CString GetRefLv() const;
const CString GetRefSx() const;
const CString GetRefSy() const;
//for setup dialog combo box ItemString
const CString GetSynMode (const SynMode&) const;
const CString GetDisplayMode (const DisPlay&) const;
const CString GetDisplayDigits(const DisDigits&) const;
const CString GetAvgingMode (const AvgMode&) const;
const CString GetBrigUnit (const BrigUnit&) const;
const CString GetCalStandard (const CalStand&) const;
//Get and Set of CA-SDK
void SetSynMode (const SynMode&); const float GetSynMode() const;
void SetDisplayMode (const DisPlay&); const long GetDisplayMode() const;
void SetDisplayDigits(const DisDigits&); const long GetDisplayDigits() const;
void SetAvgingMode (const AvgMode&); const long GetAvgingMode() const;
void SetBrigUnit (const BrigUnit&); const long GetBrigUnit() const;
void SetCalStandard (const CalStand&); const long GetCalStandard() const;
private: //for setup CA-SDK parameter
const float chooseSynMode (const SynMode&) const;
const int chooseDisplayMode (const DisPlay&) const;
const int chooseDisplayDigits(const DisDigits&) const;
const int chooseAvgingMode (const AvgMode&) const;
const int chooseBrigUnit (const BrigUnit&) const;
const int chooseCalStandard (const CalStand&) const;
private: //for real CA-210 USB connect initial
const BOOL initCreatCa200();
const BOOL initConnectCa210();
const BOOL initAttachCa();
const BOOL initAttchProbe();
#ifdef _CA210DEBUG
const CString GetSetupValue() const;
void debugMessageBox(const CString&) const;
#endif
};
#endif
Ca210real .cpp
初始化,初始化很多東西
CA-SDK的初始化,其實是要初始化不少東西。一步一步來,一步一步切開。為了讓出問題的那一步突顯出來,所以將try-catch給分開做,每一個Exception都會顯示自己所屬的函數,萬一出錯,還會告訴我是出錯在哪一步。在這一個地方,不會和IMemory連線,因為和它連線也是要花一段時間。連上IMemory的目的就只是要切換channel,這個部份就留在觸設定的地方再連線就可以了。Ca210real::Ca210real():
ImpsbStr("1. 按「Prt Scm鍵」抓下目前的螢幕,並開小畫家貼上,另存成圖檔\n2. Mail給此程式設計者,詳細描述使用過程並將圖檔存成附件\n這是尚未預測到出現的問題。(應該不會發生的那種。)"),
m_pICa200(0), m_pICa(0), m_pIProbe(0), m_pIProbeInfo(0), m_pIMemory(0)
{
DebugCode( DBugModeBox("TRUE of Ca210real()"); )
if (initCreatCa200())
if (initConnectCa210())
if (initAttachCa())
if (initAttchProbe())
m_caState = CA_not_yet_ZeroCal;
}
const BOOL Ca210real::initCreatCa200()
{
try
{
if (m_pICa200 == 0)
m_pICa200 = new ICa200();
m_pICa200->CreateDispatch("CA200Srvr.Ca200.1");
return TRUE;
}
catch (CException* e)
{
MsgFrmt(e, "CreatCa200();出問題", "1. 檢查USB線和量筒\n2. 按確定");
m_pICa200->ReleaseDispatch();
return FALSE;
}
}
const BOOL Ca210real::initConnectCa210()
{
try
{
m_pICa200->m_bAutoRelease = TRUE;
m_pICa200->AutoConnect();
return TRUE;
}
catch (CException* e)
{
MsgFrmt(e, "LPDISPATCH pICa = m_pICa200->ConnectCa210();出問題", ImpsbStr);
m_pICa200->ReleaseDispatch();
return FALSE;
}
}
const BOOL Ca210real::initAttachCa()
{
try
{
if (m_pICa == 0)
m_pICa = new ICa();
LPDISPATCH pICa(0);
pICa = m_pICa200->GetSingleCa();
m_pICa->AttachDispatch(pICa);
return TRUE;
}
catch (CException* e)
{
MsgFrmt(e, "LPDISPATCH pICa = m_pICa200->GetSingleCa();出問題", ImpsbStr);
m_pICa200->ReleaseDispatch();
return FALSE;
}
}
const BOOL Ca210real::initAttchProbe()
{
try
{
if (m_pIProbe == 0) m_pIProbe = new IProbe();
if (m_pIProbeInfo == 0) m_pIProbeInfo = new IProbeInfo();
LPDISPATCH pIProbe(0);
pIProbe = m_pICa->GetSingleProbe();
m_pIProbe->AttachDispatch(pIProbe);
m_pIProbeInfo->AttachDispatch(pIProbe);
return TRUE;
}
catch (CException* e)
{
MsgFrmt(e, "LPDISPATCH pIProbe = m_pICa->GetSingleProbe();出問題", ImpsbStr);
m_pICa->DetachDispatch();
m_pICa200->ReleaseDispatch();
return FALSE;
}
}
Zero Cal
真實的CA-210是需要Zero Cal的,而....它總是會讓你忘記。一下要轉MEAS檔一下要轉0-Cal檔的。在此,程式上的設計會提醒你接下來該做什麼。可以發現,設計上,會有一個迴圈將try-catch包起來,try裡只有m_pICa->CalZero();這個重點。
如果出錯了,就提醒你目前岀錯的地方是Probe沒有轉到0-Cal。
再執行一次,如果轉到0-Cal則會順利開始0-Cal,但是若你無視上一次的警告訊息,這次的警告訊息就會用簡短的話來「提醒」你。
畢竟剛準備量測時,還沒集中注意力,被程式發現,會改變語氣和你對話。這種被抓包的感覺,我想多多少少會提神一下。
const CaState Ca210real::CalZero()
{
/*
連線 實機
caes 11 執行ZeroCal
例外處理:
給MessageBox
再執行ZeroCal
default 回傳FALSE 無法執行
*/
if (isOnline())
{
DebugCode( DBugModeBox("TRUE of CalZero()"); )
int flag(0);
do
{
try
{
m_pICa->CalZero();
flag = 0;
}
catch (CException* e)
{
if (flag < 1)
MsgFrmt(e,"Probe還沒轉至0-Cal就執行Zero Cal", "1. 將量測筒轉至0-Cal檔。\n2. 按「確定」");
else
MsgFrmt("1. 將量測筒轉至0-Cal檔。\n2. 按「確定」");
SetOnline();
flag++;
}
} while (flag);
return m_caState = CA_ZeroCalMode;
}
else
{
DebugCode( DBugModeBox("CalZero() Offline."); )
return m_caState = CA_Offline;
}
}
取得量測值
和ZeroCal()一樣,用一個迴圈將try-catch包起來,不過,在此有一件特別的事要提醒,就是這一段程式碼,實現無形的Zero Cal,自然而然的完成了Zero Cal,你再也不需要記得,CA-210剛啟動時要Zero Cal。m_pICa->Measure(0)如果出錯,有兩個原因
- 還沒ZeroCal
- 量測時疑似抓值太快造成出錯的不明原因
這兩個原因,我們都在catch處理。
如果沒有出錯,大多就是ZeroCal已完成,還要看一下,現在的Probe是不是還在0-Cal,還沒切換到MEAS。
catch的部份,先確定有連線再看看,前CA-SDK的狀態是否已經ZeroCal。
再各別處理之。
const CaState Ca210real::Measure()
{
CaState Mode = m_caState;
if(isOnline())
{
DebugCode( DBugModeBox("TRUE of Measure()"); )
int flag = 0;
do
{
try
{
m_pICa->Measure(0);
//已經ZeroCal,檢查檔位是否正確
if (m_pIProbe->GetLv() < 0.01)
Mode = CA_ZeroCalMode; //is0-Cal檔
else
Mode = CA_MsrMode; //已ZeroCal, 檔位正確
flag = 0;
}
catch (CException* e)
{
//MsrError
SetOnline();
if (m_caState == CA_not_yet_ZeroCal) //還沒ZeroCal
{
if (CalZero() == CA_Offline)
Mode = CA_Offline;
++flag;
}
else
{
TCHAR buf[255];
e->GetErrorMessage(buf, 255);
++flag;
if (flag > 10)
//重覆太多次,導致類當機的情況。
break;
else
//在這不做任何動作,重覆執行迴圈內的東西。
continue;
}
}
} while (flag);
}
return Mode;
}
自動抓值量測
為了互動上的設計,出現了一種自己判斷目前是否可以抓值的程式段,降低使用者使用時操作的IO設備以及降低操作人手。const MsrAiState Ca210real::MsrAI(const float& MsrDeviation)
{
DebugCode( DBugModeBox("TRUE of MsrAI(float MsrDeviation)"); )
//第一筆資料暫存空間 //宣告誤差值計算空間
float XFristValue = 0.0, deltaX = 0.0,
YFristValue = 0.0, deltaY = 0.0,
ZFristValue = 0.0, deltaZ = 0.0, deltaAll;
if ( Measure() == CA_MsrMode )
{
//抓參考值
XFristValue = m_pIProbe->GetX();
YFristValue = m_pIProbe->GetY();
ZFristValue = m_pIProbe->GetZ();
if ( Measure() == CA_MsrMode )
{
//誤差取絕對值
deltaX = ((XFristValue-m_pIProbe->GetX()) >= 0) ? XFristValue - m_pIProbe->GetX() : m_pIProbe->GetX() - XFristValue;
deltaY = ((YFristValue-m_pIProbe->GetY()) >= 0) ? YFristValue - m_pIProbe->GetY() : m_pIProbe->GetY() - YFristValue;
deltaZ = ((ZFristValue-m_pIProbe->GetZ()) >= 0) ? ZFristValue - m_pIProbe->GetZ() : m_pIProbe->GetZ() - ZFristValue;
deltaAll = deltaX * deltaY * deltaZ;
if (deltaAll < MsrDeviation ) return MA_InDeviation;//門檻值內
else return MA_OutDeviation;//門檻值外
}
else
return MA_nonMsr;
}
else
return MA_nonMsr; //無效量測,可能是沒連線之類的
}
讓程式知道目前量測的LCM是幾吋的
量測幾吋的LCM就要切換到對應的Channel,Channel的名稱都會記錄這是適用幾吋,將其字串取出,就可以少問使用者一個const CString Ca210real::GetLcmSize()
{
if(isOnline())
{
DebugCode( DBugModeBox("TRUE of GetLcmSize()"); )
try
{
if (m_LCMsize.IsEmpty())
m_LCMsize.Format("%s", m_pIMemory->GetChannelID().Left(2));
}
catch (CException* e)
{
MsgFrmt(e, "模組尺寸大小設定出問題", ImpsbStr);
m_LCMsize.Format("-1");
}
}
else
m_LCMsize.Format("-1");
return m_LCMsize;
}
設定CA-210的相關選項
重新將CA-SDK介面設計得和Setup CA的概念一樣。在CaSetupDlg時,程式碼將會更加精鍊。const float Ca210real::GetRangeColor1() const
{
float clr1, clr2;
m_pICa->GetAnalogRange(&clr1, &clr2);
return clr1;
}
const float Ca210real::GetRangeColor2() const
{
float clr1, clr2;
m_pICa->GetAnalogRange(&clr1, &clr2);
return clr2;
}
const float Ca210real::GetRangeFAM() const
{
float FMA;
m_pICa->GetFMAAnalogRange(&FMA);
return FMA;
}
const CString Ca210real::GetRefSx() const
{
float Lv, Sx, Sy;
m_pIMemory->GetReferenceColor(m_pIProbe->GetId(), &Sx, &Sy, &Lv);
CString strSx;
strSx.Format("%1.4f", Sx);
return strSx;
}
const CString Ca210real::GetRefSy() const
{
float Lv, Sx, Sy;
m_pIMemory->GetReferenceColor(m_pIProbe->GetId(), &Sx, &Sy, &Lv);
CString strSy;
strSy.Format("%1.4f", Sy);
return strSy;
}
const CString Ca210real::GetRefLv() const
{
float Lv, Sx, Sy;
m_pIMemory->GetReferenceColor(m_pIProbe->GetId(), &Sx, &Sy, &Lv);
CString strLv;
strLv.Format("%f", Lv);
return strLv;
}
const CString Ca210real::GetRefProbe() const
{
long CalProbe, RefProbe, CalMode;
m_pIMemory->GetMemoryStatus(m_pIProbe->GetNumber(), &CalProbe, &RefProbe, &CalMode);
CString str;
str.Format("%ld", RefProbe);
return str;
}
const CString Ca210real::GetCalProbe() const
{
long CalProbe, RefProbe, CalMode;
m_pIMemory->GetMemoryStatus(m_pIProbe->GetNumber(), &CalProbe, &RefProbe, &CalMode);
CString str;
str.Format("%ld", CalProbe);
return str;
}
const CString Ca210real::GetCalMode() const
{
long CalProbe, RefProbe, CalMode;
m_pIMemory->GetMemoryStatus(m_pIProbe->GetNumber(), &CalProbe, &RefProbe, &CalMode);
CString str;
str.Format("%ld", CalMode);
return str;
}
//////////////////////////////////////////////////////////////////////////
void Ca210real::SetSynMode(const SynMode& SmType)
{
m_pICa->SetSyncMode(chooseSynMode(SmType));
}
const float Ca210real::chooseSynMode(const SynMode& SmType) const
{
switch(SmType)
{
case SM_NTSC: return 0.0;
case SM_PAL: return 1.0;
case SM_EXT: return 2.0;
case SM_UNIV: return 3.0;
case SM_INT: return 4.0;
default: return -1.0;
}
}
const CString Ca210real::GetSynMode(const SynMode& SmType) const
{
switch(SmType)
{
case SM_NTSC: return "NTSC";
case SM_PAL: return "PAL";
case SM_EXT: return "EXT";
case SM_UNIV: return "UNIV";
case SM_INT: return "INT";
default: return "No this Mode";
}
}
const float Ca210real::GetSynMode() const
{
return m_pICa->GetSyncMode();
}
//////////////////////////////////////////////////////////////////////////
void Ca210real::SetDisplayMode(const DisPlay& DpType)
{
m_pICa->SetDisplayMode(chooseDisplayMode(DpType));
}
const int Ca210real::chooseDisplayMode(const DisPlay& DpType) const
{
return (int)DpType;
}
const CString Ca210real::GetDisplayMode(const DisPlay& DpType) const
{
switch(DpType)
{
case DP_Lvxy: return "xyLv";
case DP_duvT: return "duvTLv"; //return "duvT";
case DP_Analyzer_NoDisplay: return "RGB"; //return "Analyzer mode";
case DP_Analyzer_Gstand: return "RGB(G)"; //return "Analyzer mode(G)";
case DP_Analyzer_Rstand: return "RGB(R)"; //return "Analyzer mode(R)";
case DP_dudv: return "u'v'Lv'"; //return "u'v'";
case DP_FMA: return "FMA";
case DP_XYZ: return "XYZ";
case DP_JEITA: return "JEITA";
default: return "No this Mode";
}
}
const long Ca210real::GetDisplayMode() const
{
return m_pICa->GetDisplayMode();
}
//////////////////////////////////////////////////////////////////////////
void Ca210real::SetDisplayDigits(const DisDigits& DdType)
{
m_pICa->SetDisplayDigits(chooseDisplayDigits(DdType));
}
const int Ca210real::chooseDisplayDigits(const DisDigits& DdType) const
{
switch(DdType)
{
case DD_3DisDigits: return 0;
case DD_4DisDigits: return 1;
default: return -1;
}
}
const CString Ca210real::GetDisplayDigits(const DisDigits& DdType) const
{
switch(DdType)
{
case DD_3DisDigits: return "3";
case DD_4DisDigits: return "4";
default: return "Out of SPEC";
}
}
const long Ca210real::GetDisplayDigits() const
{
return m_pICa->GetDisplayDigits();
}
//////////////////////////////////////////////////////////////////////////
void Ca210real::SetAvgingMode(const AvgMode& AmType)
{
m_pICa->SetAveragingMode(chooseAvgingMode(AmType));
}
const int Ca210real::chooseAvgingMode(const AvgMode& AmType) const
{
switch(AmType)
{
case AM_SLOW: return 0;
case AM_FAST: return 1;
case AM_AUTO: return 2;
default: return -1;
}
}
const CString Ca210real::GetAvgingMode(const AvgMode& AmType) const
{
switch(AmType)
{
case AM_SLOW: return "Slow";
case AM_FAST: return "Fast";
case AM_AUTO: return "Auto";
default: return "No this Mode";
}
}
const long Ca210real::GetAvgingMode() const
{
return m_pICa->GetAveragingMode();
}
//////////////////////////////////////////////////////////////////////////
void Ca210real::SetBrigUnit(const BrigUnit& BuType)
{
m_pICa->SetBrightnessUnit(chooseBrigUnit(BuType));
}
const int Ca210real::chooseBrigUnit(const BrigUnit& BuType) const
{
switch(BuType)
{
case BU_fL: return 0;
case BU_cdm2: return 1;
default: return -1;
}
}
const CString Ca210real::GetBrigUnit(const BrigUnit& BuType) const
{
switch(BuType)
{
case BU_fL: return "fL";
case BU_cdm2: return "cd/m2";
default: return "No this Unit";
}
}
const long Ca210real::GetBrigUnit() const
{
return m_pICa->GetBrightnessUnit();
}
//////////////////////////////////////////////////////////////////////////
void Ca210real::SetCalStandard(const CalStand& CsType)
{
m_pICa->SetCalStandard(chooseCalStandard(CsType));
}
const int Ca210real::chooseCalStandard(const CalStand& CsType) const
{
switch(CsType)
{
case CS_6500K: return 1;
case CS_9300K: return 2;
default: return -1;
}
}
const CString Ca210real::GetCalStandard(const CalStand& CsType) const
{
switch(CsType)
{
case CS_6500K: return "6500K";
case CS_9300K: return "9300K";
default: return "Out of SPEC";
}
}
const long Ca210real::GetCalStandard() const
{
return m_pICa->GetCalStandard();
}
設定警告標示的標準格式
將錯誤訊息標準化的方式之一,就是將它做成專屬的函式或類別。在此使用相同的函式,使得CA-SDK複雜的錯誤訊息可以翻譯成讓使用者明白的文字訊息,只不過,有時候會有點囉嗦。void Ca210real::MsgFrmt(CException* e, const CString& mean, const CString& steps)
{
CString str;
TCHAR buf[255];
e->GetErrorMessage(buf, 255);
str.Format("糟糕!!!出現ERROR!!!\n\n原廠錯誤訊息:\n%s\n\n看不懂沒關係,意思就是:\n「%s」\n\n你只要做:\n%s", buf, mean, steps);
AfxMessageBox(str);
}
第二次的警告訊息
可以發現Measure和ZeroCal的功能中,都有一個迴圈將try-catch包起來,而第二次警告訊息總是精簡用字,因為發呆時被抓包,總是不會受到親切的訊息。void Ca210real::MsgFrmt(const CString& steps)
{
CString str;
str.Format("你發呆嗎?\n%s", steps);
AfxMessageBox(str);
}
沒有留言:
張貼留言