Command Translator for Medical Device Testing Senior Design Dec05-05 Final Report Client Guidant Corporation Faculty Advisors Professor John Lamont Professor Ralph Patterson III Team Members Adam Guy, CprE Justin Koob, CprE Marc McKee, EE Adam Mishler, CprE REPORT DISCLAIMER NOTICE DISCLAIMER: This document was developed as a part of the requirements of an electrical and computer engineering course at Iowa State University, Ames, Iowa. This document does not constitute a professional engineering design or a professional land surveying document. Although the information is intended to be accurate, the associated students, faculty, and Iowa State University make no claims, promises, or guarantees about the accuracy, completeness, quality, or adequacy of the information. The user of this document shall ensure that any such use does not violate any laws with regard to professional licensing and certification requirements. This use includes any work resulting from this student-prepared document that is required to be under the responsible charge of a licensed engineer or surveyor. This document is copyrighted by the students who produced this document and the associated faculty advisors. No part may be reproduced without the written permission of the senior design course coordinator. December 14, 2005
79
Embed
Command Translator for Medical Device Testingseniord.ece.iastate.edu/projects/archive/dec0505/Deliverables... · Command Translator for Medical Device Testing Senior Design Dec05-05
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Command Translator for
Medical Device Testing
Senior Design Dec05-05
Final Report
Client
Guidant Corporation
Faculty Advisors
Professor John Lamont
Professor Ralph Patterson III
Team Members Adam Guy, CprE
Justin Koob, CprE
Marc McKee, EE
Adam Mishler, CprE
REPORT DISCLAIMER NOTICE
DISCLAIMER: This document was developed as a part of the requirements of an electrical and computer engineering course at Iowa State University, Ames, Iowa. This document does not constitute a professional engineering design or a professional land surveying document. Although the information is intended to be accurate, the associated students, faculty, and Iowa State University make no claims, promises, or guarantees about the accuracy, completeness, quality, or adequacy of the information. The user of this document shall ensure that any such use does not violate any laws with regard to professional licensing and certification requirements. This use includes any work resulting from this student-prepared document that is required to be under the responsible charge of a licensed engineer or surveyor. This document is copyrighted by the students who produced this document and the associated faculty advisors. No part may be reproduced without the written permission of the senior design course coordinator.
December 14, 2005
i
Table of Contents List of Figures ................................................................................................................ iii List of Tables ................................................................................................................. iv List of Definitions ........................................................................................................... v 1 Section 1: Introductory Material................................................................................. 1 1.1 Executive Summary .................................................................................... 1 1.2 Acknowledgement ...................................................................................... 2 1.3 Problem Statement ...................................................................................... 2
1.3.1 General Problem Statement ........................................................................ 2 1.3.2 General Solution Approach......................................................................... 3
1.3.2.1 GPIB Bus Overview .................................................................... 3 1.4 Operating Environment............................................................................... 4 1.5 Intended Users and Intended Uses.............................................................. 4
2.4 Detailed design.......................................................................................... 17 2.4.1 System Integration .................................................................................... 17 2.4.2 NI-Device Component .............................................................................. 19 2.4.3 Custom C++ Code .................................................................................... 20
2.4.3.1 Parser Function .......................................................................... 21 2.4.3.2 Command Process Functions..................................................... 22
The thorough testing of all medical devices is an important process. Government
agencies require the certification of all software and hardware used for medical
application. The translator device will allow the team’s client, Guidant, to use
existing, certified software with upgraded testing instrumentation. The
application of this device will allow for minimal re-certification while utilizing
government certified software.
4.8 References
[1] Keithley Instruments, Inc., Model 236/237/238 Source Measurement Unit’s
Operators Manual, Rev. E, March 2001, Viewed April 10, 2005,
http://www.keithley.com
44
[2] Keithley Instruments, Inc., Model 2410 Source Measurement Unit’s User’s
Manual, Rev. G, May 2002, Viewed March 5, 2005,
http://www.keithley.com
[3] Al-Dhaher, A. H. G., Development of Microcontroller/FPGA-based
systems, International Journal of Engineering Education, 2004, Vol. 20,
No. 1, pp. 52-60, Viewed April 1, 2005, http://www.ijee.dit.ie/latestissues/
45
4.9 Appendices The following appendices contain the C++ code used for the translator.
Appendix A contains the header file CSimpleDeviceFramework.h, while appendix
B contains CSimpleDeviceFramework.cpp.
Appendix A /////////////////////////////////////////////////////////////////////////////// // // File: // // CSimpleDeviceFramework.h // // Purpose: // // This file defines the framework for a simple device based on NI-Device. // // This class defines a simple device controlled by IEEE 488.2 commands. // The defined behavior for this class is to: // // 1) Respond to Device Clear messages // 2) Respond to Device Trigger messages // 3) Respond to Status Byte Requests // 4) Respond to the IEEE 488.2 Identification Query ("*IDN?") with an // IEEE 488.2 compatible response // 5) Use the IEEE 488.2 MAV bit for service requests. Accepts "*SRE 16" // to turn on the MAV bit in the SRE register, "*SRE 0" to disable // the MAV bit in the SRE register, and "*SRE?" to retrieve the // current state of the SRE Register. // // This class is derived publicly from CGpibDevice, which is derived from // C4882Device. Therefore, this simple device has the resources necessary to // communicate across GPIB using the IEEE-488.2 protocol. // // Notice that certain virtual methods *must* be overridden as documented // in the C4882Device class (C4882Device.h). // /////////////////////////////////////////////////////////////////////////////// #include <string> using std::string; // Make sure this header file is included only once per compilation unit #if !defined (___csimpledeviceframework_h___) #define ___csimpledeviceframework_h___ ////////////////////////////////////////////////////////////////////////////// // // Include files // ////////////////////////////////////////////////////////////////////////////// #if !defined (___cgpibdevice_h___) #include "CGpibDevice.h" #endif ////////////////////////////////////////////////////////////////////////////// // // Forward Declarations // //////////////////////////////////////////////////////////////////////////////
46
class C4882MsgBuffer; ////////////////////////////////////////////////////////////////////////////// // // Class definition // ////////////////////////////////////////////////////////////////////////////// class CSimpleDeviceFramework : private CGpibDevice { public: /////////////////////////// // // Construction/Destruction // /////////////////////////// // Constructor for the simple device framework. CSimpleDeviceFramework (); // Destructor for the simple device framework. This method frees any // resources that were allocated for an object of this class. virtual ~CSimpleDeviceFramework (); /////////////////// // // Interface Status // /////////////////// // This method returns true if the framework was constructed // successfully. Otherwise, false is returned. bool IsConstructedSuccessfully () const; ///////////////////////// // // Interface Management // ///////////////////////// // This method enables the interface to communicate over GPIB // using the passed in Bus specific parameters. The passed in // pDeviceDescription is used to store a description of the // interface to be printed during each event handler invokation. // This method returns true if the I/O could be enabled, and false // otherwise. bool EnableGpibIo( const char * pDeviceDescription, unsigned char PrimaryAddress ); private: ////////////////////////////// // // Private enumeration // ///////////////////////////// enum { // This is the bit in the IEEE 488.2 status byte that represents // indicates that a message is available. kStatusByteMsgAvailableBit = 0x10 };
47
////////////////////////////// // // Overridden Event Handlers // ////////////////////////////// // This Event Handler is invoked when the device receives a // message, such as "*IDN?". The 'Event' parameter describes the // conditions under which the given message was received. The 'pMsgBuf' // parameter contains the received message; inherited from C4882Device. virtual void InputQueueEventHandler ( eInputQueueEvent Event, C4882MsgBuffer * pMsgBuf ); // This event handler is invoked when a Response Message is removed // from the Output Queue by the Controller. Notice that a Controller // can remove a Response Message by reading the message from the Queue // or by sending a Device Clear message. The 'Event' parameter // describes how the Response Message was removed from the Output // Queue. The 'pMsgBuf' parameter contains the message that has been // removed from the Output Queue; inherited from C4882Device. virtual void OutputQueueEventHandler ( eOutputQueueEvent Event, C4882MsgBuffer * pMsgBuf ); // This event handler is invoked when the device receives a Device // Clear message; inherited from C4882Device. virtual void DeviceClearEventHandler (); // This event handler is invoked when the device receives a Device // Trigger message; inherited from C4882Device. virtual void DeviceTriggerEventHandler (); // This event handler is invoked when NI-Device detects an unrecoverable // software or hardware error; inherited from C4882Device. virtual void ExceptionEventHandler ( eExceptionEvent Event ); // This event handler is invoked when NI-Device detects a change // in the remote/local state of the device; inherited from C4882Device. virtual void RemoteLocalEventHandler ( eRemoteLocalState State ); ////////////////// // // Value Semantics // ////////////////// // Copy constructor. This object is not to be copied, so the // copy constructor is made private. CSimpleDeviceFramework ( const CSimpleDeviceFramework & SrcObj ); // Assignment operator. This object is not to be assigned, so // the assignment operator is made private. CSimpleDeviceFramework & operator = ( const CSimpleDeviceFramework & SrcObj ); ////////////////////////// // // Private Helper Methods //
48
////////////////////////// // This method stores the device description void _StoreDeviceDescription ( const char * pDeviceDescription, eStatusMessage & rStatus ); // This method allocates the required message buffers void _CreateMessageBuffers (eStatusMessage & rStatus); // This method deallocates the allocated message buffers void _DestroyMessageBuffers (); // This method enables the appropriate event handlers void _EnableEventHandlers (eStatusMessage & rStatus); // This method displays information about the device void _DisplayDeviceInformation (); // This method displays the specified information void _DisplayInformation ( char * pInformation ); // This method displays information about a method void _DisplayMethodInformation ( char * pMethodDescription ); // This method displays information about an event void _DisplayEventInformation ( char * pEventDescription ); // This method displays information about an action void _DisplayActionInformation ( char * pActionDescription ); // This method displays information about an error void _DisplayErrorInformation ( char * pErrorDescription, eStatusMessage Status ); // This method parses a given input message received by the device // and responds if appropriate. This parser is not fully IEEE 488.2 // compliant. // // It recognizes and responds to single commands or queries, and ignores // subsequent commands in a compound command. It correctly parses *IDN?, // *SRE?, and *SRE n, where 'n' is a decimal integer. It recognizes // invalid uses of these commands, such as *IDN? XYZ, or *SRE, and // reports them as invalid. This parser is not meant to provide a full // 488.2 compliant implementation, but rather to demonstrate the // capabilities of NI-Device. void _ParseMessage ( C4882MsgBuffer * pMsgBuf ); // This method processes a *IDN? qury and returns the appropriate // IEEE 488.2 identification response. void _ProcessIdnQuery (); // This method processes a *SRE? query and returns the current value // of the SRE register. void _ProcessSreQuery (); // This method processes a *SRE n command and sets the current SRE // register to the value n.
49
void _ProcessSreCommand ( const void * pArgument, unsigned long ArgumentSize ); void processCommandD( char* command ); void processCommandF( char* command ); void processCommandL( char* command ); void processCommandB( char* command ); void processCommandH( char* command ); void processCommandN( char* command ); void processCommandG( char* command ); void sendData( const char* data ); ////////////////// // // Private Members // ////////////////// // This member stores this information to be returned from *IDN?, By // definition, the *IDN? response contains four comma separated fields: // Field 1 returns the manufacturer // Field 2 returns the instrument model number // Field 3 returns the serial number // Field 4 returns the firmware level const char * m_ID; // Description for this device char * m_pDeviceDescription; // Input buffer for the device. C4882MsgBuffer * m_pInputBuffer; // Output buffer for the device. C4882MsgBuffer * m_pOutputBuffer; // Status byte of the device unsigned char m_StatusByte; // Service Request Enable Register unsigned char m_SRERegister; // Stores whether a device was enabled successfully bool m_IoEnabled; // This member variable stores whether the constructor completed // successfully. bool m_ConstructedSuccessfully; }; // end of class CSimpleDeviceFramework
50
#endif // end #if !defined (___csimpledeviceframework_h___)
Appendix B ////////////////////////////////////////////////////////////////////////////// // // File: // // CSimpleDeviceFramework.cpp // // Purpose: // // Implementation of CSimpleDeviceFramework - refer to the header file, // CSimpleDeviceFramework.h, for a detailed description of what each // method is intended to do, and for the inheritance hierarchy of // the methods implemented here. // // Notice that many of the method calls return a status parameter with // which you can check the success or failure of the method invocation. // In this example, we perform error checking only on the most important // calls, such as initialization and enabling the input queue. Error // checking of all calls is highly encouraged for production software. // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Include files // ////////////////////////////////////////////////////////////////////////////// // Ensure compatibility with different standard library implementations. namespace std {} using namespace std; #include <string> #include <windows.h> using std::string; // Include the interface file for this class #if !defined (___csimpledeviceframework_h___) #include "CSimpleDeviceFramework.h" #endif // Includes the definition of the parser used for this simple example #if !defined (___csimpleparser_h___) #include "CSimpleParser.h" #endif // Includes the definition of C4882MsgBuffer #if !defined (___C4882MsgBuffer_h___) #include "C4882MsgBuffer.h" #endif // Includes the standard I/O library for printing diagnostic information // to the console. #include <cstdio> // Includes the definition of strcpy #include <cstring> // Includes the definition of isdigit #include <cctype> // Includes Labview write function #include "writeGpib.h"
51
// Include the HPIB VISA #include <visa.h> ////////////////////////////////////////////////////////////////////////////// // // Implementation // ////////////////////////////////////////////////////////////////////////////// /*used to determine if current or voltage will be sourced source = false -> voltage sourced source = true -> current sourced */ bool source = false; int delay = 0; CSimpleDeviceFramework::CSimpleDeviceFramework () : m_ID ("NATIONAL INSTRUMENTS, " "SIMPLE IEEE 488.2 DEVICE, " "0x1234, " "0\n" ), m_pDeviceDescription (NULL), m_pInputBuffer (NULL), m_pOutputBuffer (NULL), m_StatusByte (0), m_SRERegister (0), m_IoEnabled (false), m_ConstructedSuccessfully (false) { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; _CreateMessageBuffers (_Status); if (NIDEVICE_STATUS_SUCCESS == _Status) { m_ConstructedSuccessfully = true; } } // CSimpleDeviceFramework CSimpleDeviceFramework::~CSimpleDeviceFramework () { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; // Disable the interface if I/O has been previously enabled. if (m_IoEnabled) { m_IoEnabled = false; _Status = C4882Device::DisableInterface (); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation( "Unable to disable the interface", _Status ); } } // Release allocated resources _DestroyMessageBuffers (); // Delete the stored Device Description. if (NULL != m_pDeviceDescription) { delete m_pDeviceDescription; }
52
} // ~CSimpleDeviceFramework bool CSimpleDeviceFramework::IsConstructedSuccessfully () const { return m_ConstructedSuccessfully; } // IsConstructedSuccessfully bool CSimpleDeviceFramework::EnableGpibIo ( const char * pDeviceDescription, unsigned char Pad ) { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; if (false == IsConstructedSuccessfully()) { _DisplayErrorInformation ( "The framework was not constructed successfully", NIDEVICE_STATUS_DEVICE_ERROR ); return false; } // Disable the interface if I/O has been previously enabled. if (m_IoEnabled) { _Status = C4882Device::DisableInterface (); if (NIDEVICE_STATUS_SUCCESS != _Status) { // Failed disabling the device _DisplayErrorInformation( "Unable to disable the current enabled interface.", _Status ); return false; } // Clear the state of various member variables when we are disabled. m_IoEnabled = false; m_StatusByte = 0; m_SRERegister = 0; } // Store the Device Description _StoreDeviceDescription ( pDeviceDescription, _Status ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to Store the Device Description.", _Status ); return false; } // Display the device information after the device description string // has been copied to the member variable. _DisplayDeviceInformation (); _DisplayMethodInformation ( "CSimpleDeviceFramework::EnableGpibIo" );
53
// Enable Event Handlers _EnableEventHandlers (_Status); if (NIDEVICE_STATUS_SUCCESS != _Status) { // Error message will be printed by the internal method. return false; } // Enable Interface _Status = CGpibDevice::EnableInterface ( Pad ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation( "Unable to enable the interface.", _Status ); return false; } // Interface was successfully enabled. m_IoEnabled = true; // Enable the Input Queue to begin receiving messages. _Status = C4882Device::EnableInputQueue ( m_pInputBuffer ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation( "Unable to enable the input queue", _Status ); return false; } // We were able to successfully enable the GPIB I/O. _DisplayInformation ("Device successfully created\n\n"); return true; } // EnableGpibIo //////////////////// // // Event Handlers // //////////////////// void CSimpleDeviceFramework::InputQueueEventHandler ( eInputQueueEvent Event, C4882MsgBuffer * pMsgBuf ) { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; // Display information to the console _DisplayDeviceInformation (); _DisplayMethodInformation ( "CSimpleDeviceFramework::InputQueueEventHandler." ); switch (Event) { // If we received a complete message
54
case END_MSG_RECEIVED: _DisplayEventInformation ("END_MSG_RECEIVED"); // Parse the input message and respond appropriately. // // Normally the parser runs in a separate thread context. In this // case, pass the message buffer to the parser and return. _ParseMessage ( pMsgBuf ); // END message acknowledgement must be performed after any query // has been detected. Since query detection is completed in the // _ParseMessage call above, acknowledgement of the end message // is done here. // // Normally an END message is passed to the parser after the // input message. When the parser parses the END message, it should // invoke the following call. The parser used in this example does // not allow the END message to be passed in, so the END message // is acknowledged here. Refer to the Multi-Threaded example for a // more realistic example of the interactions between the I/O control // and the parser. _Status= C4882Device::AcknowledgeEndOfMessage(); // Treat the status NIDEVICE_STATUS_DEVICE_CLEAR_ACTIVE as a warning // since it is a non-fatal error. To treat it as a warning, change // the status back to success. if (NIDEVICE_STATUS_DEVICE_CLEAR_ACTIVE == _Status) { _Status = NIDEVICE_STATUS_SUCCESS; } else if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation( "Could not acknowledge end of message.", _Status ); return; } break; case BUFFER_IS_FULL: _DisplayEventInformation ("BUFFER_IS_FULL"); // Parse the input message and respond appropriately. // // Normally the parser runs in a separate thread context. In this // case, pass the message buffer to the parser and return. _ParseMessage ( pMsgBuf ); break; case MSG_UNTERMINATED: _DisplayEventInformation ("MSG_UNTERMINATED"); // Note: This is an UNTERMINATED condition. The action to // take when an UNTERMINATED condition occurs is // defined in Section 6.3.2.2 of the IEEE 488.2 standard. // If status reporting were implemented, we would set the // Query Error bit in the Standard Event Status Register. // We also have the option of parsing or ignoring the // contents of the incomplete input buffer. We choose to
55
// parse the buffer. // If the input queue was not enabled, pMsgBuf will be NULL. If no // data was received before the UNTERMINATED condition was detected, // the message length will be zero. // // Normally the parser runs in a separate thread context. In this // case, pass the message buffer (if any) and the UNT message to the // parser and return. if ( (NULL != pMsgBuf) && (0 != pMsgBuf->GetMsgLength ()) ) { _ParseMessage ( pMsgBuf ); } // Normally an UNT message is passed to the parser after the // input message (if any). When the parser parses the UNT message, // it should invoke the following call. The parser used in this // example does not allow UNT messages to be passed in, so the UNT // message is acknowledged here. Refer to the Multi-Threaded example // for a more realistic example of the interactions between the I/O // control and the parser. _Status = C4882Device::AcknowledgeMsgUnterminated(); // Treat the status NIDEVICE_STATUS_DEVICE_CLEAR_ACTIVE as a warning // since it is a non-fatal error. To treat it as a warning, change // the status back to success. if (NIDEVICE_STATUS_DEVICE_CLEAR_ACTIVE == _Status) { _Status = NIDEVICE_STATUS_SUCCESS; } else if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Could not acknowledge the message unterminated condition.", _Status ); return; } break; case TRIGGER_RECEIVED: _DisplayEventInformation ("TRIGGER_RECEIVED"); // Note: This situation is a Command Error. The action to take // when the parser detects a Command Error is defined in // section 6.1.6.1.1 of IEEE 488.2. If status reporting // were implemented, we would set the Command Error bit in // the Standard Event Status Register. We also have the // option of parsing or ignoring the contents of the incomplete // input buffer. Since the Command Error is received after // the data, we choose to parse the data first. // If the input queue was not enabled, pMsgBuf will be NULL. If no // data was received before the UNTERMINATED condition was detected, // the message length will be zero. // // Normally the parser runs in a separate thread context. In this // case, pass the message buffer (if any) and the GET message to the // parser and return. Refer to the Multi-Threaded example for a // more realistic example of the interactions between the I/O control // and the parser. if (
56
(NULL != pMsgBuf) && (0 != pMsgBuf->GetMsgLength ()) ) { _ParseMessage ( pMsgBuf ); } break; } // We need to request service if we have a new reason for service. // For this simplified example, we only have to take into account // the MAV bit. Normally this algorithm a slightly more complex due // to other bits. For a better example, review the multithreaded // example. // // A new reason for service exists if: // 1) The MAV bit in the Status Byte transitions from false to // true. In this example, we know that if the MAV bit is set // in the Status Byte, it was just set by the method // '_ParseMessage'. // 2) The MAV bit in the Service Request Enable Register is true. if ( (kStatusByteMsgAvailableBit & m_StatusByte) && (kStatusByteMsgAvailableBit & m_SRERegister) ) { _DisplayActionInformation ( "Requesting Service due to Message Available." ); // Note that we ignore the status return value C4882Device::RequestService (); } // If necessary, re-enable the input queue to receive more messages. Note // that it is possible to receive a NULL message buffer with the // TRIGGER_RECEIVED and MSG_UNTERMINATED events. if (NULL != pMsgBuf) { // Enable the input queue to begin receiving messages. _Status = C4882Device::EnableInputQueue (pMsgBuf); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Could not re-enable the input queue.", _Status ); } } // Display an extra linefeed for proper formatting _DisplayInformation ("\n"); } // InputQueueEventHandler void CSimpleDeviceFramework::OutputQueueEventHandler ( eOutputQueueEvent Event, C4882MsgBuffer * pMsgBuf ) { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; // Display information to the console _DisplayDeviceInformation (); _DisplayMethodInformation ( "CSimpleDeviceFramework::OutputQueueEventHandler."
57
); switch (Event) { case MESSAGE_SENT: // If a message has been broken apart into multiple message buffers, // the next message buffer to be sent would be queued here. _DisplayEventInformation ("MESSAGE_SENT"); break; case MSG_REQUESTED: // Note: The MSG_REQUESTED event must be enabled by the method // EnableMsgRequestedEvents before they can be used. This // example does not use MSG_REQUESTED events. // // EnableMsgRequestedEvents() enables NI-Device to dispatch // the message requested events. A message requested event // is generated when the Controller requests a response message. _DisplayEventInformation ("MSG_REQUESTED"); break; case MSG_INTERRUPTED: // Note: This is an INTERRUPTED condition. The action to // take when an INTERRUPTED condition occurs is // defined in Section 6.3.2.3 of the IEEE 488.2 standard. // The output queue is cleared automatically, and if // status reporting were implemented, we would set the // Query Error bit in the Standard Event Status Register. _DisplayEventInformation ("MSG_INTERRUPTED"); break; case CLEAR_RECEIVED: _DisplayEventInformation ("CLEAR_RECEIVED"); break; } // We no longer have a message to send, so clear the MAV bit from // the Status Byte. m_StatusByte &= ~kStatusByteMsgAvailableBit; _Status = UpdateStatusByte ( m_StatusByte ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Could not update the status byte.", _Status ); } // If we were requesting service, cancel the request. We can do this since // the only reason why we request service is if we have a message available. if (kStatusByteMsgAvailableBit & m_SRERegister) { _DisplayActionInformation ( "Cancelling Request for Service due to Message No Longer Available." ); // Note that we ignore the status return value; production software may // want to check for an error here C4882Device::CancelRequestForService (); } // Display an extra linefeed for proper formatting _DisplayInformation ("\n");
58
} // OutputQueueEventHandler void CSimpleDeviceFramework::DeviceClearEventHandler () { // Display information to the console _DisplayDeviceInformation (); _DisplayMethodInformation ( "CSimpleDeviceFramework::DeviceClearEventHandler" ); // Display an extra linefeed for proper formatting _DisplayInformation ("\n"); } // DeviceClearEventHandler void CSimpleDeviceFramework::DeviceTriggerEventHandler () { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; // Display information to the console _DisplayDeviceInformation (); _DisplayMethodInformation ( "CSimpleDeviceFramework::DeviceTriggerEventHandler" ); // As defined in the IEEE 488.2 specification, a device trigger is treated // as an END message. Hence the END message is acknowledged here. _Status = C4882Device::AcknowledgeEndOfMessage (); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Could not acknowledge the end of message condition.", _Status ); } // Display an extra linefeed for proper formatting _DisplayInformation ("\n"); } // DeviceTriggerEventHandler void CSimpleDeviceFramework::ExceptionEventHandler (eExceptionEvent Event) { // Display information to the console _DisplayDeviceInformation (); _DisplayMethodInformation ( "CSimpleDeviceFramework::ExceptionEventHandler" ); switch (Event) { case HARDWARE_FAULT: _DisplayEventInformation ("HARDWARE_FAULT"); break; case HARDWARE_REMOVED: _DisplayEventInformation ("HARDWARE_REMOVED"); break; case SOFTWARE_FAULT: _DisplayEventInformation ("SOFTWARE_FAULT"); break; }
59
// Display an extra linefeed for proper formatting _DisplayInformation ("\n"); } // ExceptionEventHandler void CSimpleDeviceFramework::RemoteLocalEventHandler ( eRemoteLocalState State ) { // Display information to the console _DisplayDeviceInformation (); _DisplayMethodInformation ( "CSimpleDeviceFramework::RemoteLocalEventHandler" ); switch (State) { case LOCAL_STATE: _DisplayEventInformation ("LOCAL_STATE"); break; case REMOTE_STATE: _DisplayEventInformation ("REMOTE_STATE"); break; case LOCAL_LOCKOUT_STATE: _DisplayEventInformation ("LOCAL_LOCKOUT_STATE"); break; case REMOTE_LOCKOUT_STATE: _DisplayEventInformation ("REMOTE_LOCKOUT_STATE"); break; } // Display an extra linefeed for proper formatting _DisplayInformation ("\n"); } // RemoteLocalEventHandler /////////////////////////// // // Private Helper Methods // /////////////////////////// void CSimpleDeviceFramework::_StoreDeviceDescription ( const char * pDeviceDescription, eStatusMessage & rStatus ) { rStatus = NIDEVICE_STATUS_SUCCESS; // Set the Device Description if (NULL == pDeviceDescription) { rStatus = NIDEVICE_STATUS_PARAMETER_ERROR; _DisplayErrorInformation ( "NULL pDeviceDescription was passed in.", rStatus ); return; }
60
m_pDeviceDescription = new char [strlen(pDeviceDescription) + 1]; if (NULL == m_pDeviceDescription) { // Failed allocating the Device Description rStatus = NIDEVICE_STATUS_INSUFFICIENT_MEMORY; _DisplayErrorInformation ( "Unable to allocate memory for Device Description", rStatus ); return; } // Store the Device Description strcpy ( m_pDeviceDescription, pDeviceDescription ); } // _StoreDeviceDescription void CSimpleDeviceFramework::_CreateMessageBuffers ( eStatusMessage & rStatus ) { // Initialize status to success to start. rStatus = NIDEVICE_STATUS_SUCCESS; // Allocate input buffer of default size. The default size is defined in // C4882MsgBuffer.h m_pInputBuffer = new C4882MsgBuffer (); if (NULL == m_pInputBuffer) { // Failed allocating input buffer rStatus = NIDEVICE_STATUS_INSUFFICIENT_MEMORY; _DisplayErrorInformation ( "Unable to create the input message buffer.", rStatus ); return; } if (!m_pInputBuffer->IsMsgBufferOk ()) { // Something is wrong with input buffer rStatus = NIDEVICE_STATUS_INSUFFICIENT_MEMORY; _DisplayErrorInformation ( "Input Message Buffer is not okay.", rStatus ); return; } // Allocate output buffer of default size. The default size is defined in // C4882MsgBuffer.h m_pOutputBuffer = new C4882MsgBuffer (); if (NULL == m_pOutputBuffer) { // Failed allocating output buffer rStatus = NIDEVICE_STATUS_INSUFFICIENT_MEMORY; _DisplayErrorInformation ( "Unable to create the output message buffer.", rStatus );
61
return; } if (!m_pOutputBuffer->IsMsgBufferOk ()) { // Something is wrong with output buffer rStatus = NIDEVICE_STATUS_INSUFFICIENT_MEMORY; _DisplayErrorInformation ( "Output Message Buffer is not okay.", rStatus ); return; } } // _CreateMessageBuffers void CSimpleDeviceFramework::_DestroyMessageBuffers () { if (NULL != m_pInputBuffer) { delete m_pInputBuffer; m_pInputBuffer = NULL; } if (NULL != m_pOutputBuffer) { delete m_pOutputBuffer; m_pOutputBuffer = NULL; } } // _DestroyMessageBuffers void CSimpleDeviceFramework::_EnableEventHandlers ( eStatusMessage & rStatus ) { // Enable the device trigger event handler rStatus = EnableDeviceTriggerEventHandler (); if (NIDEVICE_STATUS_SUCCESS != rStatus) { // Failed enabling device trigger event handler. _DisplayErrorInformation ( "Unable to enable the trigger event handler.", rStatus ); return; } // Enable the exception event handler rStatus = EnableExceptionEventHandler (); if (NIDEVICE_STATUS_SUCCESS != rStatus) { // Failed enabling exception event handler. _DisplayErrorInformation ( "Unable to enable the exception event handler.", rStatus ); return; } // Enable the remote/local event handler. We are enabling this in enhanced // mode to see all four events of the remote/local state machine. rStatus = EnableRemoteLocalEventHandler ( REMOTE_LOCAL_ENHANCED_MODE );
62
if (NIDEVICE_STATUS_SUCCESS != rStatus) { // Failed enabling exception event handler. _DisplayErrorInformation ( "Unable to enable the remote/local event handler.", rStatus ); return; } } // _EnableEventHandlers void CSimpleDeviceFramework::_DisplayDeviceInformation () { // Only print if the device description is not NULL. if (NULL != m_pDeviceDescription) { printf ( "Device Description: %s", m_pDeviceDescription ); } } // _DisplayDeviceInformation // Display the information about the device void CSimpleDeviceFramework::_DisplayInformation ( char * pInformation ) { // Only print if the method information is not NULL. if (NULL != pInformation) { printf ( "%s", pInformation ); } } // _DisplayInformation void CSimpleDeviceFramework::_DisplayMethodInformation ( char * pMethodDescription ) { // Only print if the method information is not NULL. if (NULL != pMethodDescription) { printf ( "Method: %s\n", pMethodDescription ); } } // DisplayMethodInformation void CSimpleDeviceFramework::_DisplayEventInformation ( char * pEventDescription ) { // Only print if the method information is not NULL. if (NULL != pEventDescription) { printf ( "Event: %s\n", pEventDescription ); } } // _DisplayEventInformation
63
void CSimpleDeviceFramework::_DisplayActionInformation ( char * pActionDescription ) { // Only print if the method information is not NULL. if (NULL != pActionDescription) { printf ( "Action: %s\n", pActionDescription ); } } // _DisplayActionInformation void CSimpleDeviceFramework::_DisplayErrorInformation ( char * pErrorDescription, eStatusMessage Status ) { // Only print if the error information is not NULL. if (NULL != pErrorDescription) { printf ( "Error: %s\n" "Cause of failure: %s\n", pErrorDescription, C4882Device::StatusDescription (Status) ); } } // _DisplayErrorInformation ////////////////// // // Parser Methods // ////////////////// void CSimpleDeviceFramework::_ParseMessage ( C4882MsgBuffer * pMsgBuf ) { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; int i = 0; printf ( "Message Length: %lu\n" "Message: ", pMsgBuf->GetMsgLength () ); //write the message to the screen fwrite ( pMsgBuf->GetBuffer (), 1, pMsgBuf->GetMsgLength (), stdout ); // Flush the fwrite to the display. fflush (stdout); // Display an extra linefeed for proper formatting _DisplayInformation ("\n"); char* commandBuffer = (char*)pMsgBuf->GetBuffer(); char command = *commandBuffer; switch(command) {
64
case 'D': processCommandD(commandBuffer); break; case 'F': processCommandF(commandBuffer); break; case 'B': processCommandB(commandBuffer); break; case 'H': processCommandH(commandBuffer); break; case 'N': processCommandN(commandBuffer); break; case 'G': { QueryDetected(); processCommandG(commandBuffer); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ("Error: Unable to Acknowledge a query",_Status); } break; } } } // _ParseMessage void CSimpleDeviceFramework::_ProcessIdnQuery () { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; // Notice that we are making the assumption that the entire // identification string for this device can fit into the // output buffer. // Note that by dereferencing the output buffer, it is automatically cast // to char *, which is the type expected by strcpy. strcpy (*m_pOutputBuffer, m_ID); m_pOutputBuffer->SetMsgLength (strlen (m_ID)); // Queue the response message with NI-Device. This implementation violates // the IEEE 488.2 standard since we are queueing a response message with // SendEnd=true (default parameter) before we have parsed the END message. // Normally the response message should be placed in an internal output // buffer and should only be queued to NI-Device when the END message has // been parsed or the internal buffer is full. // // ...Note that some parameters are left at their default settings. _Status = C4882Device::QueueResponseMsg (m_pOutputBuffer); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to queue the response string", _Status ); return; } // Set the Message Available (MAV) bit in the Status Byte m_StatusByte |= kStatusByteMsgAvailableBit; _Status = C4882Device::UpdateStatusByte ( m_StatusByte
65
); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to update the status byte.", _Status ); } _DisplayActionInformation ( "Queued device identification string." ); } // _ProcessIdnQuery void CSimpleDeviceFramework::_ProcessSreQuery () { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; // Note that by dereferencing the output buffer, it is automatically cast // to char *, which is the type expected by sprintf and strlen. sprintf ( *m_pOutputBuffer, "%d\n", m_SRERegister ); m_pOutputBuffer->SetMsgLength (strlen (*m_pOutputBuffer)); // Queue the response message with NI-Device. This implementation violates // the IEEE 488.2 standard since we are queueing a response message with // SendEnd=true (default parameter) before we have parsed the END message. // Normally the response message should be placed in an internal output // buffer and should only be queued to NI-Device when the END message has // been parsed or the internal buffer is full. // // ...Note that some parameters are left at their default settings. _Status = C4882Device::QueueResponseMsg (m_pOutputBuffer); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to queue contents of Service Request Enable Register.", _Status ); return; } // Set the Message Available (MAV) bit in the Status Byte m_StatusByte |= kStatusByteMsgAvailableBit; _Status = C4882Device::UpdateStatusByte ( m_StatusByte ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to update the status byte.", _Status ); return; } _DisplayActionInformation ( "Queued contents of Service Request Enable Register." ); } // _ProcessSreQuery
66
void CSimpleDeviceFramework::_ProcessSreCommand ( const void * pArgument, unsigned long ArgumentSize ) { // *SRE requires an ASCII format decimal number in the range 0 to 255 if ( (0 == ArgumentSize) || (3 < ArgumentSize) ) { // This situation is a Command Error. The action to take when // the parser detects a Command Error is defined in section // 6.1.6.1.1 of IEEE 488.2. _DisplayInformation ( "Invalid parameter: Expected decimal number ranging from\n" " 0 through 255 following *SRE command.\n" ); return; } size_t _Index = 0; const char * _pDecimalNumber = static_cast <const char *> (pArgument); unsigned int _NumericData = 0; for (_Index = 0; _Index < ArgumentSize; _Index++) { if (0 == isdigit (_pDecimalNumber [_Index])) { // This situation is a Command Error. The action to take when // the parser detects a Command Error is defined in section // 6.1.6.1.1 of IEEE 488.2. _DisplayInformation ( "Invalid parameter: Expected decimal number ranging from\n" " 0 through 255 following *SRE command.\n" ); return; } _NumericData = (10 * _NumericData) + (_pDecimalNumber [_Index] - 0x30); } if (_NumericData <= 255) { // Update Service Request Enable Register m_SRERegister = static_cast <unsigned char> (_NumericData); _DisplayActionInformation ( "Updated Service Request Enable Register." ); } else { // This situation is a Command Error. The action to take when // the parser detects a Command Error is defined in section // 6.1.6.1.1 of IEEE 488.2. _DisplayInformation ( "Invalid parameter: Expected decimal number ranging from\n" " 0 through 255 following *SRE command.\n" ); } } // _ProcessSreCommand void CSimpleDeviceFramework::processCommandD(char* command) { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN;
67
int i = 0; int commandOptionNumber = *(command+1) - 48; char parser = *(command+3); char displayMessage[20]; for(i = 1; parser != 'X'; i++) { displayMessage[i-1] = parser; parser = *(command+3+i); } displayMessage[i] = '\0'; /*char commandTest[] = "DISP:TEXT \"Test from NI-Device\""; writeGpibDevice(); printf("testing\n"); //invoke labview instrument assistant to send the data down the secondary */ ViSession defaultRM, vi; char buf [256] = {0}; /* Open session to GPIB device at address 5 */ viOpenDefaultRM (&defaultRM); viOpen (defaultRM, "GPIB0::5::INSTR", VI_NULL,VI_NULL, &vi); /* Initialize device */ viPrintf (vi, "*RST\n"); /* Send an *IDN? string to the device */ //viPrintf (vi, "DISP:TEXT \"Test from NI-Device\"\n"); viPrintf (vi, "DISP:TEXT \"%s\"\n", displayMessage); //Attempt at Querying follows............................... /* char responseMessage[] = "Response Delivered Successfully\0"; strcpy (*m_pOutputBuffer, responseMessage); m_pOutputBuffer->SetMsgLength (strlen (responseMessage)); _Status = C4882Device::QueueResponseMsg (m_pOutputBuffer); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to queue the device identification string.", _Status ); return; } // Set the Message Available (MAV) bit in the Status Byte m_StatusByte |= kStatusByteMsgAvailableBit; _Status = C4882Device::UpdateStatusByte ( m_StatusByte ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to update the status byte.", _Status ); } _DisplayActionInformation (
68
"Queued device identification string." ); .............................................*/ /* Read results */ //viScanf (vi, "%t", &buf); /* Print results */ //printf ("Instrument identification string: %s\n", buf); /* Close session */ viClose (vi); viClose (defaultRM); } void CSimpleDeviceFramework::processCommandF(char* command) { int i = 0; int function = -1; //check to make sure that the source is defined if(*(command + 1) != ',') { source = (*(command + 1))-48; //check if function is defined if((*(command + 3) == '0') || (*(command +3) == '1')) { function = *(command + 3); } } else { //check to make sure that the function is defined if((*(command + 2) == '0') || (*(command +2) == '1')) { function = *(command + 2); } } } void CSimpleDeviceFramework::processCommandL(char* command) { int i = 0; char level; int range = -1; //check to make sure that the level is defined if(*(command + 1) != ',') { level = *(command + 1); //check if range is defined if((*(command + 3) >= '0') && (*(command + 3) <= '10')) { range = *(command + 3); } } else { //check to make sure that the range is defined if((*(command + 2) >= '0') && (*(command + 2) <= '10')) { range = *(command + 2); } } //lookup the new command from the database or wherever
69
//invoke labview instrument assistant to send the data down the secondary } void CSimpleDeviceFramework::processCommandB(char* command) { int i = 0; int level = -1; int range = -1; //will only support level of up to 6 volts level = (*(command + 1))-48; //range always 0, not supported range = (*(command + 3))-48; //will only support delays of up to 9 seconds delay = (*(command + 5))-48; ViSession defaultRM, vi; char buf [256] = {0}; /* Open session to GPIB device at address 5 */ viOpenDefaultRM (&defaultRM); viOpen (defaultRM, "GPIB0::5::INSTR", VI_NULL,VI_NULL, &vi); viPrintf (vi, "TRIG:SEQ:DEL %d\n", delay); viPrintf (vi, "TRIG:SEQ:SOUR BUS\n"); if(delay > 0 && source == false) { viPrintf (vi, "SOUR:VOLT:TRIG %d\n", level); } if(delay == 0 && source == false) { viPrintf (vi, "SOUR:VOLT %d\n", level); } if(delay > 0 && source == true) { viPrintf (vi, "SOUR:CURR:TRIG %d\n", level); } if(delay == 0 && source == true) { viPrintf (vi, "SOUR:CURR %d\n", level); } /* Send an *IDN? string to the device */ //viPrintf (vi, "DISP:TEXT \"Test from NI-Device\"\n"); //viPrintf (vi, "DISP:TEXT \"%s\"\n", displayMessage); //Attempt at Querying follows............................... /* char responseMessage[] = "Response Delivered Successfully\0"; strcpy (*m_pOutputBuffer, responseMessage); m_pOutputBuffer->SetMsgLength (strlen (responseMessage)); _Status = C4882Device::QueueResponseMsg (m_pOutputBuffer); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to queue the device identification string.", _Status ); return; }
70
// Set the Message Available (MAV) bit in the Status Byte m_StatusByte |= kStatusByteMsgAvailableBit; _Status = C4882Device::UpdateStatusByte ( m_StatusByte ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to update the status byte.", _Status ); } _DisplayActionInformation ( "Queued device identification string." ); .............................................*/ /* Read results */ //viScanf (vi, "%t", &buf); /* Print results */ //printf ("Instrument identification string: %s\n", buf); /* Close session */ viClose (vi); viClose (defaultRM); } void CSimpleDeviceFramework::processCommandH(char* command) { //Can only support IMM trigger, so tell the power supply to work with Immediate trigger ViSession defaultRM, vi; char buf [256] = {0}; /* Open session to GPIB device at address 5 */ viOpenDefaultRM (&defaultRM); viOpen (defaultRM, "GPIB0::5::INSTR", VI_NULL,VI_NULL, &vi); viPrintf (vi, "TRIG:SEQ:SOUR BUS\n"); viClose (vi); viClose (defaultRM); } void CSimpleDeviceFramework::processCommandN(char* command) { ViSession defaultRM, vi; char buf [256] = {0}; /* Open session to GPIB device at address 5 */ viOpenDefaultRM (&defaultRM); viOpen (defaultRM, "GPIB0::5::INSTR", VI_NULL,VI_NULL, &vi); viPrintf (vi, "OUTPUT:STATE on\n"); viPrintf(vi, "INIT\n"); viPrintf(vi, "*TRG\n"); viClose (vi); viClose (defaultRM); } void CSimpleDeviceFramework::processCommandG(char* command) {
} outputString = outputString + buf; break; } case 8: { //not supported break; } } outputString = outputString + '\0'; printf("Send this to the Guidant Controller: "); while(outputString[counter] != '\0') { printf("%c", outputString[counter]); counter = counter + 1; } sendData(outputString.c_str()); //close the connection to the instrument viClose (vi); viClose (defaultRM); } void CSimpleDeviceFramework::sendData(const char* data) { eStatusMessage _Status = NIDEVICE_STATUS_UNKNOWN; // Notice that we are making the assumption that the entire // identification string for this device can fit into the // output buffer. // Note that by dereferencing the output buffer, it is automatically cast // to char *, which is the type expected by strcpy. strcpy (*m_pOutputBuffer, data); m_pOutputBuffer->SetMsgLength (strlen (data)); // Queue the response message with NI-Device. This implementation violates // the IEEE 488.2 standard since we are queueing a response message with // SendEnd=true (default parameter) before we have parsed the END message. // Normally the response message should be placed in an internal output // buffer and should only be queued to NI-Device when the END message has // been parsed or the internal buffer is full. // // ...Note that some parameters are left at their default settings. _Status = C4882Device::QueueResponseMsg (m_pOutputBuffer); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation ( "Unable to queue the device identification string.", _Status ); return; } // Set the Message Available (MAV) bit in the Status Byte m_StatusByte |= kStatusByteMsgAvailableBit; _Status = C4882Device::UpdateStatusByte ( m_StatusByte ); if (NIDEVICE_STATUS_SUCCESS != _Status) { _DisplayErrorInformation (
73
"Unable to update the status byte.", _Status ); } _DisplayActionInformation ( "Queued response message" ); }