/****************************************************************************** * * (C) Copyright WDI 2010 * ****************************************************************************** * * FILE: epp.h * * PROJECT: AFT Sensors * * SUBPROJECT: . * * Description: Embedded part configuration protocol. * Protocol design for accessing configuration of the part. * ****************************************************************************** * * Change Activity * Defect Date Developer Description * Number DD/MM/YYYY Name * ======= ========== ================ ======================================= * 21/09/2009 Andrew L. Initial version * 02/11/2010 Chris O. * 15/11/2010 Chris O. Added synchronization objects for * multithreaded applications * *****************************************************************************/ #pragma once #include "atf_def.h" #define DtTypeSize(dt) (((dt)&DtDataType)==DtDwordEnm ? 4 : (((dt)&DtDataType)>>4)) #define DtGetDataType(dt) ((dt)&DtDataType) #define INVALID_IDX -1 typedef enum { ErrOK = 0, ErrNoAccess = 1, ErrWrongType = 2, ErrOutOfBound = 3, ErrInvalid = 4, ErrUnavailable = 5, ErrNotSupported = 6, ErrSntaxError = 7, ErrNoresources = 8, ErrInternal = 9, ErrOperFailed = 10, ErrTimeout = 11, ErrChksum = 12, ErrUnknown } EppErrorCodes; #define ErrNamesTab const char * g_eppErrorNames[] = \ { \ "0-ErrOK", \ "1-ErrNoAccess", \ "2-ErrWrongType", \ "3-ErrOutOfBound", \ "4-ErrInvalid", \ "5-ErrUnknown", \ "6-ErrNotSupported", \ "7-ErrSntaxError", \ "8-ErrNoresources", \ "9-ErrInternal", \ "10-ErrOperFailed", \ "11-ErrTimeout", \ "12-ErrChksum", \ "ErrUnknown" \ }; #ifdef __cplusplus #include "tserial.h" #include "logger.h" typedef unsigned char Combuf_Char; class CEpp : public Tserial { // communication buffer enum { MAX_COM_BUFFER_SIZE = 5000 }; Combuf_Char* p_commBuff; public: // query code for data types enum { QcParamInfo = 1, QcParamName = 2, QcParamComment = 3, QcParamError = 4, // most recent error code visible on this parameter QcReadTime = 5, // time in seconds parameter was read most recently QcWriteTime = 6, // time in seconds parameter was written most recently QcValueCurrent = 7, QcValueMax = 8, QcValueMin = 9, QcValueSetDate = 10, QcEnumValueExclusive = 11, QcEnumValueCombined = 12, QcEnumName = 13, QcEnumAllParamInfo = 15, }; // #define TagGetTag(tg) ((tg)&0xf) // session commands enum { SessionCmdRead = 'R', SessionCmdWrite = 'W', SessionCmdReadResponse = 'r', }; // transport commands enum { TransportCodingBinaryLittleEndian = 'l', TransportCodingBinaryBigEndian = 'b', TransportCodingAsciiStx = '<', TransportCodingAsciiEtx = '>', TransportAck = 'A', TransportNak = 'N' }; // com port timeouts for operations taking long period of time enum { MicroStepTimeout = 10000, MakeZeroTimeout = 6000, SaveToSensorTimeout = 8000, MagnifChangeTimeout = 1000, MotorParamTimeout = 10000 }; #define EPPENTERFUN(funname) saveToLog2(CLogger::LogLow, "%s%s", funname, " - entered\n"); #define EPPEXITFUN(funname) saveToLog2(CLogger::LogLow, "%s%s", funname, " - exited\n"); #define EPPLOGMSG(pLogMsg, LogLev) saveToLog(pLogMsg, LogLev); #define EPPLOGMSG2(LogLev, format, ...) saveToLog2(LogLev, format, __VA_ARGS__); // constructor & destructor CEpp () : Tserial(), m_pLogger(NULL), p_commBuff(NULL) { m_pFun = (ErrorFunctionPtr)0; m_pFunLocale = 0; InitializeCriticalSection(&m_cs); } CEpp (CLogger *pLogger) : Tserial(), p_commBuff(NULL) { m_pLogger = pLogger; m_pFun = (ErrorFunctionPtr)0; m_pFunLocale = 0; InitializeCriticalSection(&m_cs); } ~CEpp() { Close(); DeleteCriticalSection(&m_cs); } // serial port, communication int Open (const char *port_arg, int rate_arg); // close port void Close (); // reuse port that is already opened void Attach (HANDLE h); // leave handle opened, assuming someone else needs it void Detach (); typedef void (*ErrorFunctionPtr)(void* locale, bool bReading, EppErrorCodes err,int bid, int pid, EppDataType tag, int num, int offset); private: ErrorFunctionPtr m_pFun; void* m_pFunLocale; public: void PrintfError (void* locale, bool bReading, EppErrorCodes err, int bid, int pid, EppDataType tag, int num, int offset); void RegisterErrorFunction (ErrorFunctionPtr pFun, void* pFunLocale) { m_pFun = pFun; m_pFunLocale = pFunLocale; } // ------- generic interface -------------------- static const char* errName (EppErrorCodes err); // read the content of the element. returns ErrOK if all is fine, or other // error otherwise EppErrorCodes _ReadArray (void *to, int bid, int pid, EppDataType tag, int num = 1, int offset = 0); EppErrorCodes ReadArray (void *to, int bid, int pid, EppDataType tag, int num = 1, int offset = 0) { EppErrorCodes err = _ReadArray (to, bid, pid, tag, num, offset); if (serial_handle!=INVALID_HANDLE_VALUE && err!=ErrOK && err!=ErrUnavailable) { PrintfError(m_pFunLocale, true, err, bid, pid, tag, num, offset); } if (err==ErrOperFailed) { int bide = 0, pide = 0, err = 0; if (ReadMostRecentRetcode (&bide, &pide, (EppErrorCodes*)(&err))==ErrOK) { EPPLOGMSG2(CLogger::LogAll, "%s%c%s%d%s%d%s", "ATF Last Read Error: id=(", isalpha(bide) ? bide : '?', ", ", pide, ") Err=", err, ".\n"); } } return err; } // sets the value of the single element EppErrorCodes _WriteArray (void *from, int bid, int pid, EppDataType tag, int num = 1, int offset = 0); EppErrorCodes WriteArray (void *from, int bid, int pid, EppDataType tag, int num = 1, int offset = 0) { if (DtGetDataType(tag)==DtNoDataEnm) { num=0; offset = 0; } EppErrorCodes err = _WriteArray (from, bid, pid, tag, num, offset); if (serial_handle!=INVALID_HANDLE_VALUE && err!=ErrOK && err!=ErrUnavailable) { PrintfError(m_pFunLocale, false, err, bid, pid, tag, num, offset); } if (err==ErrOperFailed) { int bide = 0, pide = 0, err = 0; if (ReadMostRecentRetcode (&bide, &pide, (EppErrorCodes*)(&err))==ErrOK) { EPPLOGMSG2(CLogger::LogAll, "%s%c%s%d%s%d%s", "ATF Last Read Error: id=(", isalpha(bide) ? bide : '?', ", ", pide, ") Err=", err, ".\n"); } /* * * * This is code sample for testing only if (ReadIdError (bid, pid,(EppErrorCodes*)(&err))==ErrOK) { EPPLOGMSG2(CLogger::LogLow, "%s%c%s%d%s%d%s", "ATF Last Write Error 2: id=(", isalpha(bide) ? bid : '?', ", ", pid, ") Err=", err, ".\n"); } EppDataType tag; int num; int ver; if (ReadIdCommInfo (bid, pid, &tag, &num, &ver)==ErrOK) { EPPLOGMSG2(CLogger::LogLow, "%s%c%s%d%s%d%s%d%s%d%s", "ATF Last Write Error Tag: id=(", isalpha(bide) ? bid : '?', ", ", pid, "), tag=", tag, ", num=", num, ", ver=", ver, ".\n"); } */ } return err; } typedef enum { IsEppVerUnknow = 0, IsEppVerCheck = 1, IsEppVerBasic = 2, IsEppVerSupport = 3 } EppVer_Mode; static EppVer_Mode s_m_ev; // epp protocol version bool EppVerCheck(); // reads information describing the type of data used for particular communication register inline EppErrorCodes ReadIdCommInfo (int bid, int pid, EppDataType *ptag, int *pnum, int *pversion) { short commTable[4]; if (!EppVerCheck()) return ErrNotSupported; EppErrorCodes err = _ReadArray (commTable, bid, pid, (EppDataType)(QcParamInfo|DtWordEnm), 3, 0); if (err==ErrOK) { *ptag = (EppDataType)(commTable[0]); *pnum = commTable[1]; *pversion = commTable[2]; } return err; } // reads most recent status returned with particular command inline EppErrorCodes ReadIdError (int bid, int pid, EppErrorCodes* perr) { short commTable[4]; if (!EppVerCheck()) return ErrNotSupported; EppErrorCodes err = _ReadArray (commTable, bid, pid, (EppDataType)(QcParamError|DtWordEnm), 1); if (err==ErrOK) { *perr = (EppErrorCodes)(commTable[0]); } return err; } typedef struct // element describing most recent communication error { short iError; // error that has been reported addressing iMostRecentField short iField; // field that had been addressed most recently short iLen; // number of elements accessed in most recent command short iOffset; // offset in most recent command short iType; // type of the acecss and data field used in most recent command } CommMostRecent; // reads most recent return code assigned by sensor inline EppErrorCodes ReadMostRecentRetcode (int *pbid, int *ppid, EppErrorCodes* perr) { CommMostRecent commErr; if (!EppVerCheck()) return ErrNotSupported; EppErrorCodes err = _ReadArray (&commErr, 's', 20, DtWordEnm, 2); if (err==ErrOK) { *pbid = (commErr.iField >> 8) & 0xff; *ppid = commErr.iField & 0xff; *perr = (EppErrorCodes)(commErr.iError); } return err; } // restore communication. // returns: 0-failed, 1-app running, 2-boot loader reset to app int RecoverSensor(); // check for Ack character received from the other side int PingAck(); // resets sensor int Reset(); EppErrorCodes _ChangeCommTimeouts(DWORD dwTimeout); EppErrorCodes _ResetCommTimeouts(); EppErrorCodes _ChangeCommBaudrate(DWORD dwBaudRate); EppErrorCodes _GetCommBaudrate(DWORD *dwBaudrate); inline bool isSerialConnection() {return serial_handle != INVALID_HANDLE_VALUE ? true : false; } EppErrorCodes sendCmnd(Combuf_Char *pToSend, Combuf_Char *pToRecv = NULL, int iTimeout = 0, int iExpByteNum = 0); // logging CLogger *m_pLogger; void saveToLog(const char *pLogMsg, CLogger::LogLevels iLogLevel); void saveToLog2(CLogger::LogLevels iLogLevel, char *pFormat, ...); inline void setLogger(CLogger *pLogger) { m_pLogger = pLogger; } private: CRITICAL_SECTION m_cs; }; // simple critical section class #ifndef __AFXMT_H__ // defined if MIcrosoft afxmt.h is included class CCriticalSection { private: CRITICAL_SECTION m_cs; const bool m_bIsLocalCs; public: CCriticalSection() : m_bIsLocalCs(false) { InitializeCriticalSection(&m_cs); } CCriticalSection(CRITICAL_SECTION &cs) : m_bIsLocalCs (true) { m_cs = cs; } ~CCriticalSection() { if (m_bIsLocalCs) DeleteCriticalSection(&m_cs); } void Lock() { EnterCriticalSection(&m_cs); } void Unlock() { LeaveCriticalSection(&m_cs); } }; #endif // this class maintains an array of CEpp objects and track availability in current thread class CEppArr { public: enum { MAX_EPP_NUM = 8 }; static CEpp gs_epp_arr[MAX_EPP_NUM]; // global table of CEpp private: static bool gs_epp_allocated_arr[MAX_EPP_NUM]; // indicate if object is already allocated static CCriticalSection gs_cs; // to faciliate table identification static __declspec( thread ) int gst_epp_index; // current index per thread public: static int Open (const char *port_arg, int rate_arg); static void Close (); static inline int SetCurrentEppIndex(int idx) { if (idx>=0 && idx=0 && gst_epp_index