⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cppcontrol.cpp

📁 介绍控制器运动的例子
💻 CPP
字号:
// CPPControl.cpp : Simple Set and Get of flags using a console.
// The application asks the user for connection information and then allows line 
// by line input to the device.  This is an example of how a non-MFC C++ program 
// can directly use the Control and Status Interfaces, and by inference, all other 
// interfaces.  Note that this uses Status using polling, an example of Status using
// events can be found in CPPStatus project.
//
// Include Files

// STL for strings and IO 
#include <string>
#include <iostream>
#include <sstream>
#include <limits>
// using namespace std;       // uncomment this statement to avoid putting std:: everywhere

// ATL for easier use of COM 
#define _WIN32_DCOM           // Before windows.h, allows CoInitializeEx()
#include <windows.h>
#include <atlbase.h>  
CComModule _Module;
#include <atlcom.h>
#undef max  // max is a windows macro (bad), but I need to use the max in STL

// Import the BoxBridge Type Library to make COM stuff a bit easier to read
#import "..\ComACRsrvr.tlb" no_namespace named_guids

// Simple Struct/Class to hold/pass communications settings between classes.
// An alturnitive to passing this state information around would be to either
// pass around pointers (as CPPTerminal does) or make the Interfaces global.
struct ConnectData
{
  ConnectData():transport(0){ };
  ConnectData(const ConnectData &data){ assign(data); };
  long     transport;  // type of transport chosen
  long       busType;  // specific Bus Type (PCI=0, ISA=1)
  long       portNbr;  // specific Com Port 
  long       portBPS;  // speed of Com Port 
  long       cardNbr;  // identifying number for devices in bus or daisy chained or USB
  std::string  netIP;  // ethernet address
  long fullBPS() { long bps[3] = {9600,19200,38400}; if(portBPS>2) portBPS = 2; return bps[portBPS]; }
  const ConnectData& operator=(const ConnectData &data){ assign(data); return *this; }
  void assign(const ConnectData &other){
    transport = other.transport;
    busType = other.busType;
    portNbr = other.portNbr;
    portBPS = other.portBPS;
    cardNbr = other.cardNbr;
    netIP = other.netIP;
  }
};

class ACRparser
{
  // The ACRparser will determine if this is a SET or PRINT operation
  // The first character dictates what is done.  The following characters
  // are the flag number.
  // 1st Character: + Set Bit Number that follows, e.g. +128 sets bit 128
  // 1st Character: - Clr Bit Number that follows, e.g. -128 clears bit 128
  // 1st Character: ? Get Bit Number that follows, e.g. ?128 prints SET or CLR
  // 1st Character anything else, return string
public:
  enum FIRST_CHAR {FLAG_SET='+', FLAG_CLR='-', FLAG_PRN='?'};

  ACRparser(ConnectData cData) 
  { 
    // Try to connect when created
    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    m_Cntl.CreateInstance(CLSID_Control);
    m_Stat.CreateInstance(CLSID_Status);
    // Connect to Control Interface 
    m_Cntl->nBus = cData.busType;
    m_Cntl->nPort = cData.portNbr;
    m_Cntl->nBPS = cData.fullBPS();
    m_Cntl->bstrIP = _bstr_t(cData.netIP.c_str());
    m_Cntl->Connect(cData.transport,cData.cardNbr);
    // Connect to Status Interface
    m_Stat->nBus = cData.busType;
    m_Stat->nPort = cData.portNbr;
    m_Stat->nBPS = cData.fullBPS();
    m_Stat->bstrIP = _bstr_t(cData.netIP.c_str());
    m_Stat->Connect(cData.transport,cData.cardNbr);
  }

  virtual ~ACRparser() 
  { 
    // Close the COM stuff down
    m_Cntl->Disconnect();
    m_Cntl = NULL;         // Setting smart pointers to NULL is *VERY IMPORTANT*
    m_Stat->Disconnect();
    m_Stat = NULL;         // Setting smart pointers to NULL is *VERY IMPORTANT*
    CoUninitialize();
  }

  std::string DoFlag(const std::string cmd)
  {
    long bitNbr=0;        // Bit Number
    long parmNbr=0;       // p-Parameter Number
    long parmVal=0;       // p-Parameter Value
    long bitIndex=0;      // Index of bit in the p-Parameter

    std::ostringstream os;// Used to create string from number + string
    SAFEARRAY* pSA;
    long lBound = 0; 
    CComVariant vItem;    // The CComVariant is found in the atlbase.h include file
    CComVariant status;   // it will clean up SAFEARRAY when it goes out of scope.

    // Check the first character and process bit number
    switch(cmd.at(0)){

    case FLAG_SET:
      // Use the SetFlag() method in the Control Interface to set the specific bit
      m_Cntl->SetFlag(atol(cmd.substr(1).c_str()),true,true);
      m_Msg = "flag " + cmd.substr(1) + " now SET.";
      break;

    case FLAG_CLR:
      // Use the SetFlag() method in the Control Interface to clear the specific bit
      m_Cntl->SetFlag(atol(cmd.substr(1).c_str()),false,true);
      m_Msg = "flag " + cmd.substr(1) + " now CLR.";
      break;

    case FLAG_PRN:
      // Use the GetACRCustom() method in the Status Interface to find the bit's value.
      // This requires us to determine the p-parameter the bit is stored in, and at what
      // position in the Long p-parameter it occupies.  This requires some math, the use
      // of a SAFEARRAY and the help of the IsFlagSet() method in the Status Interface.

      // Do the Math
      bitNbr = atol(cmd.substr(1).c_str());
      parmNbr = 4096 + (bitNbr/32);
      bitIndex = bitNbr%32;

      // Get the value of the p_Parm, returned in a safearray
      os << "P" << parmNbr;
      status = m_Stat->GetACRCustom(_bstr_t(os.str().c_str()));
      if(status.vt & VT_ARRAY){ 
        pSA = status.parray;
        SafeArrayGetElement(pSA, &lBound, &vItem);
        if(vItem.vt!=VT_EMPTY){
          parmVal = vItem.lVal;
        }else{
          m_Msg = "Problem Getting Status";
          break;
        }
      }else{ 
        m_Msg = "Problem Getting Status";
        break;
      }

      // Check if bit set or clear
      if(m_Stat->IsFlagSet(parmVal, bitIndex)){
        m_Msg = "flag " + cmd.substr(1) + " is currently SET";
      }else{
        m_Msg = "flag " + cmd.substr(1) + " is currently CLR";
      }
      break;
    default:
      m_Msg = cmd;
      break;
    } 
    return m_Msg;
  } 

private:
  std::string m_Msg;
  IControlPtr m_Cntl;
  IStatusPtr m_Stat;
};

void getInputLong(long &in, const std::string &msg, const long inMin = 0, const long inMax = 0) {
  // The cin has problems if the proper type of data is not entered, so 
  // handel those issues in one place.  Since most of the cin is in the
  // main(), this is a global function, but could also be a class method.
  while (!(std::cin >> in) || ((inMax > inMin) && (in < inMin || in > inMax))) {
     std::cout << msg;
     std::cin.clear();
     std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
}

//-----------------------------------------------------------------------------
// Main Control Loop
//-----------------------------------------------------------------------------
int main(int argc, char* argv[])
{
  // The Interface pointers are here (before the try) to allow easy clean up in 
  // main()'s try/catch. It is important to set any smart pointers to NULL before exiting. 
  IControlPtr cCntl;
  IStatusPtr cStat;

  try{
  // Need to initialize for each thread as multithreaded
  CoInitializeEx(NULL, COINIT_MULTITHREADED);

  // Establish Communication Server
  cCntl.CreateInstance(CLSID_Control);
  cStat.CreateInstance(CLSID_Status);
  std::string ver = std::string(_com_util::ConvertBSTRToString(cCntl->bstrVersion)); // Version
  std::cout << "--------Get and Set Flags using the ComACRsrvr v" << ver << "--------\n\n";
  ConnectData cData;

  // Collect Connection Information
  cData.transport = 0;    // transport type
  cData.busType = 0;      // bus type
  cData.portNbr = 1;      // com port
  cData.portBPS = 2;      // bps of com port
  cData.netIP = "0.0.0.0";// ip address
  cData.cardNbr = 0;      // card index

  std::string portname; // transport lable
  std::string input;    // terminal input

  std::cout << "How are we connecting.  Type in a number and press <enter>\n0=Offline, 1=Bus, 2=Serial, 3=Ethernet, 4=USB: ";
  getInputLong(cData.transport, "You must enter a number between 0 - 4: ",0,4);

  switch (cData.transport){
  // Various transport types require specific extra communication data
  case 0: 
    portname = "OFFLINE"; 
    break;
  case 1: 
    portname = "BUS";
    std::cout << "What Type of bus is the device in?\n0=PCI, 1=ISA: ";
    getInputLong(cData.busType, "You must enter a number between 0 - 1: ",0,1);
    std::cout << "What is the index number of the device (usually 0):";
    getInputLong(cData.cardNbr, "You must enter a number: ");
    break;
  case 2: 
    portname = "SERIAL"; 
    std::cout << "What is the Com Port number: ";
    getInputLong(cData.portNbr, "You must enter a number between 1 - 256: ",1,256);
    std::cout << "What is the BPS of the Com Port? 0=9600, 1=19200, 2=38400: ";
    getInputLong(cData.portBPS, "You must enter a number between 0 - 2: ",0,2);
    std::cout << "What is the index number of the device (usually 0): ";
    getInputLong(cData.cardNbr, "You must enter a number: ");
    break;
  case 3: 
    portname = "ETHERNET"; 
    std::cout << "What is the ip address of the device: ";
    std::cin >> cData.netIP;
    std::cout << "What is the index number of the device (usually 0): ";
    getInputLong(cData.cardNbr, "You must enter a number: ");
    break;
  case 4: 
    portname = "USB"; 
    std::cout << "What is the index number of the device (use 0 if unsure): ";
    getInputLong(cData.cardNbr, "You must enter a number: ");
    break;
  default:
    portname = "Unknown"; 
    cData.transport = 0;
    break;
  }  

  // We do not actually use the Interfaces in main(), but just connect to verify
  // that the connection information is OK.
  // Connect to Control Interface 
  cCntl->nBus = cData.busType;
  cCntl->nPort = cData.portNbr;
  cCntl->nBPS = cData.fullBPS();
  cCntl->bstrIP = _bstr_t(cData.netIP.c_str());
  std::cout << "\nConnecting...";
  cCntl->Connect(cData.transport,cData.cardNbr);
  if(cCntl->isOffline){
    std::cout << "you have choosen not to connect, goodbye" << std::endl;
    return 0;
  }
  std::cout << "you are now connected using the " << portname << " port.\n\nEnter the word QUIT (in UPPER CASE) to exit.\n\n";
  std::cout << "Flags can be set, cleared or checked for their current state.\nUse a command prefix ";
  std::cout << "character plue a bit number, and hit enter.\nThe command prefix can be:\n+ : SET Flag\n- : CLR Flag\n? : Query Flag\nFor example, +128 sets bit 128.\n";

  // Connect to Status Interface
  cStat->nBus = cData.busType;
  cStat->nPort = cData.portNbr;
  cStat->nBPS = cData.fullBPS();
  cStat->bstrIP = _bstr_t(cData.netIP.c_str());
  cStat->Connect(cData.transport,cData.cardNbr);

  // The Application - line based data entry (i.e. type in stuff and hit enter to submit.)
  ACRparser gParse(cData);
  while ((std::cin >> input) && (input != "QUIT")){  
    std::cout << gParse.DoFlag(input) << std::endl;
  }

  // Close the COM stuff down
  cCntl->Disconnect();
  cCntl = NULL;         // Setting smart pointers to NULL is *VERY IMPORTANT*
  cStat->Disconnect();
  cStat = NULL;         // Setting smart pointers to NULL is *VERY IMPORTANT*
  CoUninitialize();

	return 0;

  // Error Handling - the errors specifically thrown by Communications Server
  // show up as COM exceptions and can be caught with the _com_error class.
  }catch(_com_error err){
    cCntl = NULL;  
    cStat = NULL;  
    CoUninitialize();
    MessageBox(NULL, err.Description(), "COM Error", MB_OK);
    return 0;
  }catch(...){
    cCntl = NULL;  
    cStat = NULL;  
    CoUninitialize();
    LPVOID lpMsgBuf;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf,0,NULL);
    MessageBox(NULL, (LPCTSTR)lpMsgBuf, "General Error", MB_OK);
    LocalFree(lpMsgBuf);
    return 0;
  } 
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -