// ips7demoDlg.cpp : implementation file
//

#include "stdafx.h"
#include <conio.h>
#include "ips7demo.h"
#include "ips7demoDlg.h"



#ifdef _DEBUG

#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define IPS7_E_NOERR		    0
#define IPS7_E_DATASIZE 	    2
#define IPS7_E_CPU_NOTFOUND	    -6
#define IPS7_E_TIMEOUT		    -1
#define IPS7_E_SOCKERR		    -7
#define IPS7_E_TYPE_NOTSUPPORTED    -10
#define IPS7_E_BADREF		    -99
#define E_DEMOEND                   4660



static BYTE
DataAreas[] = 
{
  'E', 'A', 'M', 'D', 'T','Z', // like in list box
};

#define POS_ADR 0
#define POS_DEC 1
#define POS_HEX 2
#define POS_ASCII 3

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CIPS7demoDlg dialog

CIPS7demoDlg::CIPS7demoDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CIPS7demoDlg::IDD, pParent)
    , m_strLocalTSAP(_T(""))
    , m_strRemoteTSAP(_T(""))
    , m_DBLen(_T(""))
{
	//{{AFX_DATA_INIT(CIPS7demoDlg)
    m_bOpenState = false;
	m_uCount = 1;
	m_uDBNo = 1;
	m_strIPAddr = _T("192.168.0.80");
	m_uStartAt = 0;
	m_RackNr = 0;
	m_SlotNr = 2;
	m_PLCType = 0;
	m_strIPStatus = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  m_DataArea = 'E';
  m_lErr = 0;
  m_lRef = -1;
  m_hWaitCursor   = LoadCursor (NULL, IDC_WAIT);
  m_hNormalCursor = GetCursor ();
  m_hLogo = LoadImage (NULL, "oem.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);  
  m_bUseOP = TRUE;
  m_bConnected = FALSE;
  
}

bool CIPS7demoDlg::GetTSAPFromEdit (CString &Str, BYTE *pTSAP)
{
  if (Str.GetLength() == 5 && 
      isdigit(Str.GetAt(0)) &&
      isdigit(Str.GetAt(1)) &&
      Str.GetAt(2)=='.' &&
      isdigit(Str.GetAt(3)) &&
      isdigit(Str.GetAt(4))
      )
  {
    pTSAP[0] =   ((Str.GetAt(0) - '0') << 0x04) + (Str.GetAt(1) - '0');
    pTSAP[1] =   ((Str.GetAt(3) - '0') << 0x04) + (Str.GetAt(4) - '0');
    return true;
  }
  return false;
}

void CIPS7demoDlg::DoDataExchange(CDataExchange* pDX)
  {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CIPS7demoDlg)
    DDX_Control(pDX, IDC_RDMULTI, m_ctrlRdMulti);
    DDX_Control(pDX, IDC_IP_STATUS, m_ctrlIPStatus);
    DDX_Control(pDX, IDC_USEPG, m_ctrlUsePG);
    DDX_Control(pDX, IDC_USEOP, m_ctrlUseOP);
    DDX_Control(pDX, IDC_RDREAL, m_ctrlRdReal);
    DDX_Control(pDX, IDC_RDDWORD, m_ctrlRdDWord);
    DDX_Control(pDX, IDC_SLOTNR, m_ctrlSlotNr);
    DDX_Control(pDX, IDC_RACKNR, m_ctrlRackNr);
    DDX_Control(pDX, IDC_LOGO, m_ctrlLogo);
    DDX_Control(pDX, IDC_IPADDRESS, m_ctrlIPAddress);
    DDX_Control(pDX, IDC_DBNO, m_ctrlDBNo);
    DDX_Control(pDX, IDC_STATUS, m_ctrlStatus);
    DDX_Control(pDX, IDC_RDWORD, m_ctrlRdWord);
    DDX_Control(pDX, IDC_RDBYTE, m_ctrlRdByte);
    DDX_Control(pDX, IDC_OPEN, m_ctrlOpen);
    DDX_Control(pDX, IDC_DATA_AREA, m_ctrlDataArea);
    DDX_Control(pDX, IDC_DATA, m_ctrlDataList);
    DDX_Control(pDX, IDC_CLOSE, m_ctrlClose);
    DDX_Text(pDX, IDC_COUNT, m_uCount);
    DDV_MinMaxUInt(pDX, m_uCount, 1, 2048);
    DDX_Text(pDX, IDC_DBNO, m_uDBNo);
    DDV_MinMaxUInt(pDX, m_uDBNo, 1, 65535);
    DDX_Text(pDX, IDC_IPADDRESS, m_strIPAddr);
    DDX_Text(pDX, IDC_START, m_uStartAt);
    DDV_MinMaxUInt(pDX, m_uStartAt, 0, 65535);
    DDX_Text(pDX, IDC_RACKNR, m_RackNr);
    DDV_MinMaxUInt(pDX, m_RackNr, 0, 2);
    DDX_Text(pDX, IDC_SLOTNR, m_SlotNr);
    DDV_MinMaxUInt(pDX, m_SlotNr, 0, 8);
    DDX_CBIndex(pDX, IDC_PLCTYPE, m_PLCType);
    DDX_Text(pDX, IDC_IP_STATUS, m_strIPStatus);
    DDX_Control(pDX, IDC_PLCTYPE, m_ctrlPlcType);
    DDX_Control(pDX, IDC_PLCINFO, m_ctrlGetPlcTime);
    DDX_Control(pDX, IDC_RDSTR, m_ctrlRdStr);
    DDX_Control(pDX, IDC_RDLUINT, m_ctrlRdLInt);
    DDX_Text(pDX, IDC_LOCALTSAP, m_strLocalTSAP);
    DDX_Text(pDX, IDC_REMOTETSAP, m_strRemoteTSAP);

    //}}AFX_DATA_MAP

    if (pDX->m_bSaveAndValidate)
    {
      m_bUseTSAP = (GetTSAPFromEdit (m_strLocalTSAP, m_LocalTSAP) && GetTSAPFromEdit (m_strRemoteTSAP, m_RemoteTSAP));


      m_DataArea = DataAreas[m_ctrlDataArea.GetCurSel ()];
      switch (m_DataArea)
      {
      case 'T':
      case 'Z':
        m_ctrlRdByte.EnableWindow (FALSE);
        m_ctrlDBNo.EnableWindow (FALSE);
        break;

      case 'D':
        m_ctrlDBNo.EnableWindow (TRUE);
        break;

      default:  
        m_ctrlRdByte.EnableWindow (m_bOpenState);
        m_ctrlDBNo.EnableWindow (FALSE);

      }
    }
    DDX_Control(pDX, IDC_LOCALTSAP, m_ctrlLocalTSAP);
    DDX_Control(pDX, IDC_REMOTETSAP, m_ctrlRemoteTSAP);
    DDX_Text(pDX, IDC_DBLEN, m_DBLen);
    DDX_Control(pDX, IDC_DBLEN, m_ctrlDBLen);
}

BEGIN_MESSAGE_MAP(CIPS7demoDlg, CDialog)
	//{{AFX_MSG_MAP(CIPS7demoDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_OPEN, OnOpen)
	ON_BN_CLICKED(IDC_CLOSE, OnClose)
	ON_BN_CLICKED(IDC_RDBYTE, OnRdByte)
	ON_BN_CLICKED(IDC_RDWORD, OnRdWord)
	ON_CBN_SELCHANGE(IDC_DATA_AREA, OnSelChangeDataArea)
	ON_BN_CLICKED(IDC_RDDWORD, OnRdDWord)
	ON_BN_CLICKED(IDC_RDREAL, OnRdReal)
	ON_BN_CLICKED(IDC_USEOP, OnUseOP)
	ON_BN_CLICKED(IDC_USEPG, OnUsePG)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_RDMULTI, OnRdMulti)
	//}}AFX_MSG_MAP
	ON_CBN_SELCHANGE(IDC_PLCTYPE, &CIPS7demoDlg::OnCbnSelchangePlctype)
	ON_BN_CLICKED(IDC_PLCINFO, &CIPS7demoDlg::OnBnClickedPLCInfo)
	ON_BN_CLICKED(IDC_RDSTR, &CIPS7demoDlg::OnBnClickedRdstr)
  ON_BN_CLICKED(IDC_RDLUINT, &CIPS7demoDlg::OnBnClickedRdLInt)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CIPS7demoDlg message handlers

BOOL CIPS7demoDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here

  m_ctrlDataArea.SetCurSel (0);
  m_ctrlClose.EnableWindow (FALSE);

  m_ctrlDataList.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
  m_ctrlDataList.InsertColumn  (POS_ADR,"Adr /Addr");
  m_ctrlDataList.SetColumnWidth (POS_ADR, LVSCW_AUTOSIZE_USEHEADER);
  m_ctrlDataList.InsertColumn   (POS_DEC, "Wert/Value(dec.)", LVCFMT_RIGHT);
  m_ctrlDataList.SetColumnWidth (POS_DEC, LVSCW_AUTOSIZE_USEHEADER);
  m_ctrlDataList.InsertColumn   (POS_HEX, "HEX    ", LVCFMT_RIGHT);
  m_ctrlDataList.SetColumnWidth (POS_HEX, LVSCW_AUTOSIZE_USEHEADER);
  m_ctrlDataList.InsertColumn   (POS_ASCII, "ASCII", LVCFMT_RIGHT);
  m_ctrlDataList.SetColumnWidth (POS_ASCII, LVSCW_AUTOSIZE_USEHEADER);
  CheckDlgButton (IDC_USEOP, TRUE);

  m_ctrlDataList.SetColumnWidth (POS_ADR, 80);  

  m_ctrlLogo.SetBitmap ((HBITMAP) m_hLogo);

  ShowConnectStatus ();
	SetTimer (1, 1000, NULL); //Check every 1000 ms the Status of the connection
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CIPS7demoDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CIPS7demoDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CIPS7demoDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CIPS7demoDlg::OnOpen()
{
	// TODO: Add your control notification handler code here

  if (UpdateData (TRUE))
  {
    int AccesMode = 0;    
        ////0 = OP-Verbindung zur durch Rack und Slot angegebene CPU aufbauen 
        ////1 = PG-Verbindung zur durch Rack und Slot angegebene CPU aufbauen 
        ////2 = Verbindung zu einer S7-200 über gesteckten TCP/IP-CP 
        ////3 = Verbindung einer Siemens-Logo-SPS (ab 1.60.78) 
        ////4 = Verbindung über den Kanal „Sonstige“ (ab 1.60.79) 

    if (m_PLCType == 2) // S7 200
    {
        AccesMode = 2;
    }
    else if (m_PLCType == 3) // Logo PLC
	{
        AccesMode = 3;
	}
	else
    {
      if (m_bUseOP)
          AccesMode = 0;
      else
          AccesMode = 1;
    }


    m_lRef = IPS7OpenExWithTSAP(m_strIPAddr, m_RackNr, m_SlotNr, 0,0,AccesMode,5000, 5000, 5000, m_bUseTSAP?m_LocalTSAP:NULL, m_bUseTSAP?m_RemoteTSAP:NULL);
    if (m_lRef >= 0)
    {
      //1. Zeit nachdem eine Wiederholung gemacht wird, wenn KeepAlive nicht erfolgreich
      // bei Windows nach 6 Versuchen ende!
      //2. Parameter = Idle, Ruhezeit, bis ein KeepAlive gesendet wird

//      IPS7SetKeepAlive (m_lRef, 100, 1000);
     
       m_lErr = IPS7_E_NOERR;
       SetOpenState(true);	
    }
    else
    {
      m_lErr = m_lRef;
      ShowErr ();
    }
  }
}

void CIPS7demoDlg::SetOpenState (bool bState)
{

    m_ctrlPlcType.EnableWindow(!bState);
    m_ctrlOpen.EnableWindow (!bState);
    m_ctrlClose.EnableWindow (bState);
    m_ctrlRdByte.EnableWindow (bState);
    m_ctrlRdWord.EnableWindow (bState);
    m_ctrlRdDWord.EnableWindow (bState);
    m_ctrlRdReal.EnableWindow (bState);
    m_ctrlRdMulti.EnableWindow (bState);
    m_ctrlGetPlcTime.EnableWindow (bState);
    m_ctrlRdStr.EnableWindow(bState);
    m_ctrlRdLInt.EnableWindow(bState);
    m_ctrlSlotNr.EnableWindow (!bState);
    m_ctrlRackNr.EnableWindow (!bState);
    m_ctrlIPAddress.EnableWindow (!bState);
    m_ctrlUseOP.EnableWindow (!bState);
    m_ctrlUsePG.EnableWindow (!bState);

    m_ctrlLocalTSAP.EnableWindow (!bState);
    m_ctrlRemoteTSAP.EnableWindow (!bState);
    m_bOpenState = bState;
}

void CIPS7demoDlg::OnClose()
{
	// TODO: Add your control notification handler code here
  if (m_lRef >= 0)
  {
	m_lErr = IPS7Close (m_lRef);
    SetOpenState(false);	
    m_lRef = -1;
    ShowErr ();
  }
}

CString CIPS7demoDlg::GetStatusText ()
{
  int SocketErr;
  CString S;
  
  switch (m_lErr)
  {
    case IPS7_E_NOERR:
      S = "Aktion erfolgreich. / Action was successfull!";
      break;
    
    case IPS7_E_DATASIZE:	       // angeforderter Bereich zu klein
      S = "Datenbereich in der SPS zu klein. / Data area in PLC too small!";
      break;
    
    
    case IPS7_E_CPU_NOTFOUND:	      // z.B wenn zu wenig Daten von übers Netzwerk kommen
      S = "Verbindung zur SPS konnte nicht aufgebaut werden! / Connectiom to PLC failed!";
      break;
    
    case IPS7_E_TIMEOUT:
      S = "Zeitüberlauf! / Timeout!";
      break;
    
    case IPS7_E_SOCKERR:
      SocketErr =  IPS7GetSockErr (m_lRef);
      S.Format("Socketfehler Nr: %d aufgetreten. / Socket error no:%d occurred!", SocketErr, SocketErr);
      break;
    
		case IPS7_E_NOTSUPPORTED:
		case IPS7_E_TYPE_NOTSUPPORTED:
      S = "Datentyp oder Format wird nicht unterstützt! / Data type or data format not supported!";
      break;
    
    case IPS7_E_PC_BUFSIZE:
      S = "Das Ã¼bergebene Array hat zuwenig Elemente. / The Array you passed is to small.";
      break;
    
    case IPS7_E_ALREADY_OPENED:
      S = "Die Open-Funktion wurde bereits aufgerufen. / The Open was called already.";
      break;
    
    
    case IPS7_PC_E_S7_DATATYPE_BAD_REL:
      S = "Multi-Access : PC und S7-Datentyp stehen int falscher Relation / PC and S7 -datatype beeing in bad relations";
      break;
    
    case IPS7_E_BADDATACOUNT:
      S = "Multi-Access : SPS liefert falsche Anzahl an Daten / PLC sends bad count of data";
      break;
    
    case IPS7_E_BLOCK_NOT_EXIST:
      S = "DB nicht vorhanden / DBP doesn't exist";
      break;

    case IPS7_E_FUNCTION_NOT_SUPPORTED_BY_PLC: 
      S = "Funktion von der SPS nicht unterstützt / Function not supported";
      break;

    case E_DEMOEND:  
      S = "Demozeit ist abgelaufen. Programm bitte erneut starten! / Demo time is over. Please restart application!";
      break;
    
    default:
      S.Format ("Unbekannter Fehler aufgetreten. / Unknown error occured! (%d)", m_lErr);
      break;
  }
  return (S);
}
	
void CIPS7demoDlg::ShowErr()
{
  CString S = GetStatusText ();
  m_ctrlStatus.SetWindowText (S);
  if (m_lErr)
    AfxMessageBox (S, MB_OK);
}

int CIPS7demoDlg::ReadDBLen()
{
  int Res = 0;
  if (m_DataArea == 'D')
  {
    int DBLen;
    DBLen = IPS7GetDBLen(m_lRef, m_uDBNo);
    if (DBLen < 0)
    {
      m_DBLen = "????";
      if (DBLen == IPS7_E_BLOCK_NOT_EXIST ||
          DBLen == IPS7_E_FUNCTION_NOT_SUPPORTED_BY_PLC )
        Res = 0;
      else
        Res = DBLen;
    }
    else
    {
      m_DBLen.Format("%d", DBLen);
      Res = DBLen;
    }
  }
  else
  {
    m_DBLen = "----";
  }
  m_ctrlDBLen.SetWindowText  (m_DBLen);
  return Res;
}



void CIPS7demoDlg::OnRdByte()
{
	// TODO: Add your control notification handler code here
	if (m_lRef >= 0)
  {
    if (UpdateData (TRUE))
    {
      m_ctrlDataList.SetRedraw (FALSE);
      m_ctrlDataList.DeleteAllItems ();
      SetWaitCursor ();

      m_lErr = ReadDBLen ();
      if (m_lErr >= 0)
        m_lErr = IPS7RdB (m_lRef, m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_ByteBuf);

      if (m_lErr == 0)
      {
        AddItemsToList (m_DataArea, m_uDBNo, 0, m_uStartAt, 0, m_uCount,  PC_BYTE, IPS7_BYTE, m_ByteBuf);
      }
      m_ctrlDataList.SetRedraw (TRUE);
      SetNormalCursor ();
      ShowErr ();
    }
  }
}


void CIPS7demoDlg::SetWaitCursor()
{
  SetCursor (m_hWaitCursor);
}

void CIPS7demoDlg::SetNormalCursor()
{
  SetCursor (m_hNormalCursor);
}


void CIPS7demoDlg::OnRdDWord() 
{
	if (m_lRef >= 0)
  {
    if (UpdateData (TRUE))
    {
      m_ctrlDataList.SetRedraw (FALSE);
      m_ctrlDataList.DeleteAllItems ();
      SetWaitCursor ();
      m_lErr = ReadDBLen ();
      if (m_lErr >= 0)
        m_lErr = IPS7RdDW (m_lRef, m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_DWordBuf);
      if (m_lErr == 0)
      {
        AddItemsToList (m_DataArea, m_uDBNo, 0, m_uStartAt, 0, m_uCount, PC_WORD32, IPS7_DWORD, m_DWordBuf);
      }
      m_ctrlDataList.SetRedraw (TRUE);
      SetNormalCursor ();
      ShowErr ();
    }
  }
}

void CIPS7demoDlg::OnRdWord()
{
	// TODO: Add your control notification handler code here
	if (m_lRef >= 0)
  {
    if (UpdateData (TRUE))
    {
      m_ctrlDataList.SetRedraw (FALSE);
      m_ctrlDataList.DeleteAllItems ();
      SetWaitCursor ();
      m_lErr = ReadDBLen ();
      if (m_lErr >= 0)
        m_lErr = IPS7RdPlcW (m_lRef, m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_WordBuf);
      if (m_lErr == 0)
        AddItemsToList (m_DataArea, m_uDBNo, 0, m_uStartAt, 0, m_uCount, PC_WORD16, IPS7_WORD, m_WordBuf);

      m_ctrlDataList.SetRedraw (TRUE);
      SetNormalCursor ();
      ShowErr ();
    }
  }
}

const char* CIPS7demoDlg::MakeAdrName (int DataArea, int DBNr, int PLCDataType)
{
  const char *TypeChar = "";
  switch (PLCDataType)
  {
    case IPS7_BIT: 
      if (DataArea == 'D')
        TypeChar = "X";
      break;

    case IPS7_BYTE:
      TypeChar = "B";      
      break;
    
    case IPS7_WORD:
    case IPS7_INT:
      TypeChar = "W";
      break;
    
    case IPS7_DWORD:
    case IPS7_DINT:
    case IPS7_REAL:
      TypeChar = "D";
      break;

  }
  if (DataArea == 'D')
  {
    m_strAdrName.Format ("DB%d.DB%s", DBNr, TypeChar);
  }
  else if (DataArea == 'T')
    m_strAdrName = "T ";
  else if (DataArea == 'Z')
    m_strAdrName = "Z ";
  else
  {
    m_strAdrName.Format ("%c%s", (BYTE) DataArea, TypeChar);
  }
  return (m_strAdrName);
}


void CIPS7demoDlg::OnSelChangeDataArea()
{
	// TODO: Add your control notification handler code here
  UpdateData (TRUE);
}

BOOL CIPS7demoDlg::DestroyWindow()
  {
	// TODO: Add your specialized code here and/or call the base class
  KillTimer (1); // Status Timer stoppen
  if (m_lRef >= 0)
  {
    IPS7Close (m_lRef);
    m_lRef = 0;
  }
  m_lErr = IPS7Close (m_lRef);
	

	return CDialog::DestroyWindow();
}

void CIPS7demoDlg::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
{
	// TODO: Add your specialized code here and/or call the base class
	
	CDialog::CalcWindowRect(lpClientRect, nAdjustType);
}

void CIPS7demoDlg::PostNcDestroy()
{
	// TODO: Add your specialized code here and/or call the base class
	if (m_hLogo)
    DeleteObject (m_hLogo);
	CDialog::PostNcDestroy();
}


void CIPS7demoDlg::OnRdReal() 
{
	if (m_lRef >= 0)
  {

    if (UpdateData (TRUE))
    {
      m_ctrlDataList.SetRedraw (FALSE);
      m_ctrlDataList.DeleteAllItems ();
      SetWaitCursor ();
      m_lErr = ReadDBLen ();
      if (m_lErr >= 0)
        m_lErr = IPS7RdReal (m_lRef, m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_DoubleBuf);
      if (m_lErr == 0)
        AddItemsToList (m_DataArea, m_uDBNo, 0, m_uStartAt, 0, m_uCount, PC_DOUBLE, IPS7_REAL, m_DoubleBuf, false);
      m_ctrlDataList.SetRedraw (TRUE);

      SetNormalCursor ();
      ShowErr ();
    }
  }
}


void CIPS7demoDlg::OnUseOP() 
{
  m_bUseOP = TRUE;
	
}

void CIPS7demoDlg::OnUsePG() 
{
  m_bUseOP = FALSE;
}
  

void CIPS7demoDlg::OnTimer(UINT_PTR nIDEvent) 

{
	// TODO: Add your message handler code here and/or call default
  if (nIDEvent == 1) // Timer for Connectioncheck
  {
    BOOL bConnected = TRUE;
    if (IPS7GetConnectStatus (m_lRef) <= 0)
    {
      bConnected = FALSE;
    }
    if (bConnected != m_bConnected)
    {
      m_bConnected = bConnected;
      ShowConnectStatus ();    
    }
  }
	CDialog::OnTimer(nIDEvent);
}

void CIPS7demoDlg::ShowConnectStatus()
{
  if (m_bConnected)
  {
    m_strIPStatus =  "verbunden / connected";
  }
  else
  {
    m_strIPStatus =  "nicht verbunden / not connected";
  }
  m_ctrlIPStatus.SetWindowText (m_strIPStatus);
  m_ctrlIPStatus.UpdateWindow ();
}

void CIPS7demoDlg::ShowErrInList (int Line)
{
  CString S = GetStatusText ();    
  m_ctrlDataList.SetItemText (Line, POS_DEC,S);
}


void CIPS7demoDlg::SetListItemData (int Line, int Item, int PCDataType, int PLCDataType, void *pData, bool bShowHex, int Result)
{
  CString Str;
  BYTE *pByte = (BYTE *)pData;
  double *pDouble = (double *)pData;
  
  float *pFloat = (float *)pData;
  short int  *pInt16 = (short int *)pData;
  unsigned short int *pUInt16 = (unsigned short int *)pData;
  LONG32  *pInt32 = (LONG32 *)pData;
  INT64  *pInt64 = (INT64 *)pData;

  DWORD *pUInt32= (DWORD *)pData;
  int UnitSize = 1;

  if (Result != 0)
  {
    ShowErrInList (Line);      
    return;
  }

  switch (PCDataType)
  {
    default:
    case PC_BYTE:
      Str.Format ("%d", (unsigned) pByte[Item]);
      UnitSize = sizeof (BYTE);
      break;

    case PC_WORD16:
      Str.Format ("%u", pUInt16[Item]);
      UnitSize = sizeof (WORD);
      break;

    case PC_INT16:
      Str.Format ("%d", pInt16[Item]);
      UnitSize = sizeof (short int);
      break;

    case PC_WORD32:
      Str.Format ("%lu", pUInt32[Item]);
      UnitSize = sizeof (DWORD);
      break;
      
    case PC_INT32:
      Str.Format ("%ld", pInt32[Item]);
      UnitSize = sizeof (LONG32);
      break;

    case PC_WORD64:
      Str.Format ("%llu", pInt64[Item]);
      UnitSize = sizeof (INT64);
      break;

    case PC_INT64:
      Str.Format ("%lld", pInt64[Item]);
      UnitSize = sizeof (INT64);
      break;

    case PC_FLOAT:
      Str.Format ("%.2f", (double) pFloat[Item]);
      bShowHex = false;
      UnitSize = sizeof (float);
      break;

    case PC_DOUBLE: 
      Str.Format ("%.2f", pDouble[Item]);
      UnitSize = sizeof (double);
      bShowHex = false;
      break;

		case PC_STRING:
			Str.Format ("String: Len:%d",  strlen ((const char *) pData));
			break;

  
  }
  if (PLCDataType == IPS7_TIMER)
    Str += " ms";
  m_ctrlDataList.SetItemText (Line, POS_DEC,Str);

  if (bShowHex)
  {
    int UnitSize = 1;
		BYTE HexData[8];
    switch (PLCDataType)
    {
      default:
      case IPS7_BIT:
      case IPS7_BYTE:
        UnitSize = 1;
        HexData[0] = pByte[Item * UnitSize];
        break;

      case IPS7_TIMER:
      case IPS7_COUNTER:
        bShowHex = false;
      case IPS7_WORD:
      case IPS7_INT:
        UnitSize = 2;
        HexData[0] = pByte[Item * UnitSize +1];
        HexData[1] = pByte[Item * UnitSize + 0];
        break;

      case IPS7_DWORD:
      case IPS7_DINT:
      case IPS7_REAL:
        UnitSize = 4;
        HexData[0] = pByte[Item * UnitSize + 3];
        HexData[1] = pByte[Item * UnitSize + 2];
        HexData[2] = pByte[Item * UnitSize + 1];
        HexData[3] = pByte[Item * UnitSize + 0];
        break;

      case IPS7_LINT:
      case IPS7_ULINT:
        UnitSize = 8;
        HexData[0] = pByte[Item * UnitSize + 7];
        HexData[1] = pByte[Item * UnitSize + 6];
        HexData[2] = pByte[Item * UnitSize + 5];
        HexData[3] = pByte[Item * UnitSize + 4];

        HexData[4] = pByte[Item * UnitSize + 3];
        HexData[5] = pByte[Item * UnitSize + 2];
        HexData[6] = pByte[Item * UnitSize + 1];
        HexData[7] = pByte[Item * UnitSize + 0];

        break;



    }
    CString Sx;
    CString StrAscii;
    Str.Empty ();

		if (PLCDataType == IPS7_STRING)
		{
			int i = 0;
			Str.Empty();
			while  (*pByte && i < 254)
			{
				Sx.Format ("%02X",*pByte);
				Str += Sx; 
				if (isprint (*pByte))
					StrAscii += (char )*pByte;
				else
					StrAscii += ".";
				++pByte;
				++i;
			}
		}
		else
		{
			for (int i = 0; i < UnitSize; i++)
			{
				Sx.Format ("%02X",HexData[i]);
				Str += Sx; 
				if (isprint (HexData[i]))
					StrAscii += (char )HexData[i];
				else
					StrAscii += ".";
			}
		}
    m_ctrlDataList.SetItemText (Line, POS_HEX,Str);
  
    m_ctrlDataList.SetItemText (Line, POS_ASCII,StrAscii);
  }
}

void CIPS7demoDlg::AddItemsToList (int DataArea, int DBNr, int Line, int StartAt, int StartBit, int Cnt, int PCDataType, int PLCDataType,  void *pD, bool bShowHex, int Result)
{
  int i;
  int Step = 1;
  bool bBit = false;
  int BitNr = StartBit;
  int S7ItemNr;
  
  switch (PLCDataType)
  {
    case IPS7_BIT:
      bBit = true;
      Step = 1;
      bShowHex = false;
      break;

    default:
	    
    case IPS7_TIMER:
    case IPS7_COUNTER:
      bShowHex = false;
    case IPS7_BYTE:
      Step = 1;
      break;
   

    case IPS7_WORD:
    case IPS7_INT:
      Step = 2;
      break;
    
    case IPS7_DWORD:
    case IPS7_DINT:
    case IPS7_REAL:
      Step = 4;
      break;

    case IPS7_LINT:
    case IPS7_ULINT:
      Step = 8;
      break;


		case IPS7_STRING:
			bShowHex = TRUE;
			break;
  }
  if (DataArea == 'Z' || DataArea == 'T')
  {
    Step = 1;
    bShowHex = false;
  }
  MakeAdrName (DataArea, DBNr, PLCDataType);

  S7ItemNr = StartAt;
  for (i = 0; i < Cnt; i++, Line++)
  {
    CString S;
        
    if (bBit)
    {
      S.Format ("%s%d.%d", (const char *)m_strAdrName,  S7ItemNr , BitNr);
      if (++BitNr > 7)
      {
        BitNr = 0;
        ++S7ItemNr;
      }
    }
    else
    {
      S.Format ("%s%d", (const char *)m_strAdrName,  S7ItemNr);
      S7ItemNr += Step;
    }
 
    m_ctrlDataList.InsertItem (Line, S);
    SetListItemData (Line, i, PCDataType, PLCDataType, pD, bShowHex, Result);
		if (PLCDataType == IPS7_STRING)
			break;
  }
}

void CIPS7demoDlg::InitRq (IPS7_RQ_MULTI *pRq, long DataArea, long DataType, long PcDataArea, long DBNr,  long Start, long StartBit, long Cnt, void *pData)
{
  pRq->DataArea = DataArea;
  pRq->DataType = DataType;
  pRq->DBNr = DBNr;
  pRq->Cnt = Cnt; 
  pRq->Start = Start;
  pRq->StartBit = StartBit;
  pRq->PcDataType = PcDataArea;
  pRq->Data = pData;
}


void CIPS7demoDlg::OnRdMulti() 
{
  BYTE EBits[64];
  WORD MWords[32];
  int Cnt = 10;
  int Line = 0;
  int i;

  IPS7_RQ_MULTI  Rq[10] ; // Max. 10 Aufträge;
  memset (Rq, 0, sizeof (Rq));

  Cnt = 0;

  // lese ab E 4.0 7 Bit
  InitRq (&Rq[Cnt++], 'E', IPS7_BIT, PC_BYTE, 0, 0, 0, 8, EBits); 

  BYTE DB10Bits[64];  
  // lese ab DB10.DBX1.1  32 Bit

  InitRq (&Rq[Cnt++], 'D', IPS7_BIT, PC_BYTE, 10, 1, 1, 32, DB10Bits); 


  //lese ab MB 20 10 Worte
  InitRq (&Rq[Cnt++], 'M', IPS7_WORD, PC_WORD16, 0, 10, 0, 10, MWords);

/*
  //lese ab MB 20 10 Realwerte
  double MDoubles[10];
  InitRq (&Rq[Cnt++], 'M', IPS7_REAL, PC_DOUBLE, 0, 10, 0, 10, MDoubles);

*/


/*
  //lese  DB10 ab Datenbyte 0 150 Worte
  InitRq (&Rq[Cnt++], 'D', IPS7_WORD, PC_WORD16, 10, 0, 0, 150, DB10Words);
  //lese DB20 ab Datenbyte 0 150 Worte lege diese aber als double im PC ab
	InitRq (&Rq[Cnt++], 'D', IPS7_WORD, PC_DOUBLE, 10, 0, 0, 150, DB10WordsAsDouble);

  //lese ab Timer 5 10 Timer und lege diese als int ab
  InitRq (&Rq[Cnt++], 'T', IPS7_TIMER, PC_WORD32, 0, 0, 0, 5, TimerAsInt); // T5 10 Timer
*/

  if (UpdateData (TRUE))	
  {
    m_ctrlDataList.SetRedraw (FALSE);
    m_ctrlDataList.DeleteAllItems ();
    m_ctrlDBLen.SetWindowText("----");
    SetWaitCursor ();

   
    m_lErr= IPS7RdMulti(m_lRef, Rq, Cnt);
    for (Line = 0, i = 0; i < Cnt; i++ )
    {
      AddItemsToList (Rq[i].DataArea, Rq[i].DBNr, Line, Rq[i].Start, Rq[i].StartBit, Rq[i].Cnt,  Rq[i].PcDataType,  Rq[i].DataType, Rq[i].Data,  true, Rq[i].Result);
	    if (Rq->PcDataType == PC_STRING)
	      Line++;
	    else
          Line += Rq[i].Cnt;
    }
    m_ctrlDataList.SetRedraw (TRUE);
    SetNormalCursor ();
    ShowErr ();
  }
}

void CIPS7demoDlg::OnCbnSelchangePlctype()
{
    UpdateData(TRUE);
	if (m_ctrlPlcType.GetCurSel() == 1) // S7 1200
	{
		m_RackNr = 0;
		m_SlotNr  = 1;
		m_PLCType = 1;
		UpdateData(FALSE);
	}
	else if (m_ctrlPlcType.GetCurSel() == 0) // S7 300 / 400
	{
		m_RackNr = 0;
		m_SlotNr  = 2;
		m_PLCType = 0;
		UpdateData(FALSE);
	}
	else
	{
		m_RackNr = 0;
		m_SlotNr = 1;
		m_PLCType = m_ctrlPlcType.GetCurSel();
		UpdateData(FALSE);
	}
}

void CIPS7demoDlg::OnBnClickedPLCInfo()
{
	if (m_lRef >= 0)
	{
		long Year, Month, Day, Hour,  Minute, Second, Millisecond;

  	SetWaitCursor ();

		m_lErr = IPS7GetPLCTime(m_lRef, &Year, &Month, &Day, &Hour, &Minute, &Second, &Millisecond);
		SetNormalCursor ();
		ShowErr ();
		if (1)
    //if (m_lErr == 0)
		{
			char strInfo[64];
			CString StrTime;
			StrTime.Format ("PLC-Time: %d.%d.%04d %02d:%02d:%02d + %d ms", Day, Month, Year, Hour, Minute, Second, Millisecond);
			CString Msg;
			Msg = "SPS-Info / PLC-Info\n\n";

			if (IPS7GetPLCName(m_lRef, strInfo) == 0)
			{
				Msg += "SPS-Name / Name of the PLC: '";
				Msg += strInfo;
				Msg += "'\n\n";
 			}

			if (IPS7GetModuleName(m_lRef, strInfo) == 0)
			{
				Msg += "Baugruppenname / Name of the Module: '"; 
				Msg += strInfo;
				Msg += "'\n\n";
			}

			if (IPS7GetPlantIdName(m_lRef, strInfo) == 0)
			{
				Msg += "Anlagenname  / Plant identification of PLC: '"; 
				Msg += strInfo;
				Msg += "'\n\n";
			}

  		if (IPS7GetCopyrightEntry(m_lRef, strInfo) == 0)
			{
				Msg += "Copyright Eintrag / entry: '"; 
				Msg += strInfo;
				Msg += "'\n\n";
			}

	  	if (IPS7GetModuleSNr(m_lRef, strInfo) == 0)
			{
				Msg += "Seriennummer der Baugruppe / Serial number of the module: '"; 
				Msg += strInfo;
				Msg += "'\n\n";
			}

			if (IPS7GetModuleTypeName(m_lRef, strInfo) == 0)
			{
				Msg += "Baugruppentyp / Module type name: '";
				Msg += strInfo;
				Msg += "'\n\n";
			}

		  if (IPS7GetMMCSNr(m_lRef, strInfo) == 0)
			{
				Msg += "Seriennummer der MMC / Serial number of MMC: '";
				Msg += strInfo;
				Msg += "'\n\n";
			}

			if (IPS7GetOEMId(m_lRef, strInfo) == 0)
			{
				Msg += "OEM ID der SPS / OEM ID of PLC: '"; 
				Msg += strInfo;
				Msg += "'\n\n";
			}

			if (IPS7GetLocationDesignation(m_lRef, strInfo) == 0)
			{
				Msg += "Ortskennzeichen der SPS / Location designation PLC: '";
				Msg += strInfo;
				Msg += "'\n\n";
			}
			Msg += StrTime;

			AfxMessageBox(Msg);
		}
	}
}


void CIPS7demoDlg::OnBnClickedRdstr()
{
	// TODO: Add your control notification handler code here
	if (m_lRef >= 0)
	{
		if (UpdateData (TRUE))
		{
			m_ctrlDataList.SetRedraw (FALSE);
			m_ctrlDataList.DeleteAllItems ();
			SetWaitCursor ();

			m_lErr = IPS7RdStr (m_lRef, m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_strBuf);

			if (m_lErr == 0)
			{
				AddItemsToList (m_DataArea, m_uDBNo, 0, m_uStartAt, 0, m_uCount,  PC_STRING, IPS7_STRING, m_strBuf);
			}
			m_ctrlDataList.SetRedraw (TRUE);
			SetNormalCursor ();
			ShowErr ();
		}
	}
}



void CIPS7demoDlg::OnBnClickedRdLInt()
{
  if (m_lRef >= 0)
  {
    if (UpdateData (TRUE))
    {
      m_ctrlDataList.SetRedraw (FALSE);
      m_ctrlDataList.DeleteAllItems ();
      SetWaitCursor ();

      m_lErr = ReadDBLen ();
      if (m_lErr >= 0)
        m_lErr = IPS7RdLInt(m_lRef, m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_Int64Buf);
      if (m_lErr == 0)
      {
        AddItemsToList (m_DataArea, m_uDBNo, 0, m_uStartAt, 0, m_uCount, PC_INT64, IPS7_ULINT, m_Int64Buf);
      }
      m_ctrlDataList.SetRedraw (TRUE);
      SetNormalCursor ();
      ShowErr ();
    }
  }

}
