Blog
Kom i gang med at programmere Web-IO-enheder!
Ved hjælp af det følgende C++-programeksempel kan du repræsentere din Web-IO Digital med dens indgange og udgange i et Windows-program. Du kan også skifte mellem udgangene på Web-IO.
Kom i gang - bestil en prøveversion i 30 dage.
Prøv vores produkter fra Wiesemann & Theis gratis i 30 dage ved at skrive det i ordrebekræftelsen: Ønsker at teste produktet.
Hvis du ikke ønsker at gøre brug af din returret inden for 30 dage, skal du blot betale den medfølgende faktura. Gratis forsendelse i Danmark.
- med magt,
- konfigurerede ind- og udgange,
- tilsluttet den til dit netværk,
- tildelt den en IP-adresse – hvilket med WuTility ikke er noget problem.
1. Saml de forskellige betjeningselementer og visningsobjekter i Visual C++-form.

2. Definition i header-filen for MySocket og Cweb_IO_ClientDlg
For at gemme indtastningerne i felterne IDC_IPTEXT, IDC_PORTTEXT, IDC_PASSWORDTEXT og IDC_POLLINGTEXT i private medlemsvariabler i klassen CWeb_IO_ClientDlg, er der defineret flere variabler i headerfilen.
For ikke at generere en ny variabel for hver ny sendt og modtaget besked, genereres der også private variabler i headeren. Posten i statuslinjen får også en variabel på dette tidspunkt.
private:
CString m_ip;
CString m_message1;
CString m_message2;
CString m_rcv;
CString m_password;
int m_port;
int m_range;
public:
CStatusBarCtrl*
m_statusBar;Ligeledes er nogle nødvendige metoder foruddefineret i headeren.
public:
void changeAccess(int i);
void TryConnect();
void OnConnect();
void OnDisconnect();
void checkpass();
void OnReceive();
void OnSend();
void OnClose();
void OnTimer(UINT nIDEvent);
void readAndClearCounter(CString data)For at initialisere en forbindelse nu, har vi stadig brug for en klasse, der tager sig af at sende og modtage data. Her har vi oprettet en fil ved navn MySocket, som arver fra CAsyncSocket-klassen. På denne måde overføres alle offentlige metoder for denne klasse til vores klasse og erklæres igen i overskriften. For at kunne få adgang til metoderne for CWeb_IO_ClientDlg-klassen senere, erklæres et objekt i headeren.
public:
CWeb_IO_ClientDlg*
m_client;
public:
virtual void OnReceive(int nErrorCode);
virtual void OnSend(int nErrorCode);
virtual void OnClose(int nErrorCode);3. Definition i MySocket.cpp
Da MySocket-klassen har arvet fra CAsyncSocket-klassen, er nogle af de nødvendige metoder til en kørende forbindelse overlejret. På denne måde kan applikationen senere både sende og modtage data asynkront og reagere på planlægning af forbindelsen til Web-IO-sider.
void MySocket::OnReceive(int nErrorCode)
{
m_client->OnReceive();
CAsyncSocket::OnReceive(nErrorCode);
}
void MySocket::OnSend(int nErrorCode)
{
m_client->OnSend();
CAsyncSocket::OnSend(nErrorCode);
}
void MySocket::OnClose(int nErrorCode)
{
m_client->OnClose();
CAsyncSocket::OnClose(nErrorCode);
}
void MySocket::OnConnect(int nErrorCode);
{
if(nErrorCode == 0)
{
m_client->OnConnect();
CAsyncSocket::OnConnect(nErrorCode);
}
else
{
m_client->OnDisconnect();
m_client->m_statusBar->SetText("Error while connecting!", 0, 0);
}
}4. Start af programmet
Opsætning af betjeningselementerne
Gruppen med betjeningselementerne til Web-IO spærres først for drift. Så snart en forbindelse er etableret, aktiveres alle elementer, der har et meningsfuldt format.
Hvis du vil vise beskeder i en statuslinje, oprettes der en i denne metode. Derudover overføres MySocket-klassen, så begge er knyttet til hinanden.
For at linke variabler eller metoder til applikationskomponenterne kan du bruge Visual C++ ClassWizard, og for Visual Studio 2003 og nyere den tilsvarende funktionalitet i klasseegenskaberne.
BOOL CWeb_IO_ClientDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// weitere Implementierungen...
m_statusBar = new CStatusBarCtrl;
m_statusBar->Create(WS_CHILD|WS_VISIBLE, CRect(0, 0, 0, 0), this, 0);
clientSocket.m_client = this;
changeAccess(FALSE);
SendMessage(DM_SETDEFID,
IDC_CONNECT);
return TRUE;
}void CWeb_IO_ClientDlg::changeAccess(bool b)
{
if(b == TRUE)
{
GetDlgItem(IDC_CONNECT)->EnableWindow(FALSE);
GetDlgItem(IDC_DISCONNECT)->EnableWindow(TRUE);
GetDlgItem(IDC_OUTPUT0)->EnableWindow(TRUE);
GetDlgItem(IDC_OUTPUT1)->EnableWindow(TRUE);
GetDlgItem(IDC_READALL0)->EnableWindow(TRUE);
GetDlgItem(IDC_READALL1)->EnableWindow(TRUE);
GetDlgItem(IDC_POLLING0)->EnableWindow(TRUE);
GetDlgItem(IDC_POLLING1)->EnableWindow(TRUE);
GetDlgItem(IDC_POLLINGTEXT)->EnableWindow(TRUE);
GetDlgItem(IDC_POLLINGCOUNTER)->EnableWindow(TRUE);
GetDlgItem(IDC_READ0)->EnableWindow(TRUE);
GetDlgItem(IDC_READ1)->EnableWindow(TRUE);
GetDlgItem(IDC_CLEAR0)->EnableWindow(TRUE);
GetDlgItem(IDC_CLEAR1)->EnableWindow(TRUE);
GetDlgItem(IDC_READALL)->EnableWindow(TRUE);
GetDlgItem(IDC_CLEARALL)->EnableWindow(TRUE);
}
else
{
GetDlgItem(IDC_CONNECT)->EnableWindow(TRUE);
GetDlgItem(IDC_DISCONNECT)->EnableWindow(FALSE);
GetDlgItem(IDC_OUTPUT0)->EnableWindow(FALSE);
GetDlgItem(IDC_OUTPUT1)->EnableWindow(FALSE);
GetDlgItem(IDC_INPUT0)->EnableWindow(FALSE);
GetDlgItem(IDC_INPUT1)->EnableWindow(FALSE);
GetDlgItem(IDC_READALL0)->EnableWindow(FALSE);
GetDlgItem(IDC_READALL1)->EnableWindow(FALSE);
GetDlgItem(IDC_POLLING0)->EnableWindow(FALSE);
GetDlgItem(IDC_POLLING1)->EnableWindow(FALSE);
GetDlgItem(IDC_POLLINGTEXT)->EnableWindow(FALSE);
GetDlgItem(IDC_POLLINGCOUNTER)->EnableWindow(FALSE);
GetDlgItem(IDC_COUNTERTEXT0)->EnableWindow(FALSE);
GetDlgItem(IDC_COUNTERTEXT1)->EnableWindow(FALSE);
GetDlgItem(IDC_READ0)->EnableWindow(FALSE);
GetDlgItem(IDC_READ1)->EnableWindow(FALSE);
GetDlgItem(IDC_CLEAR0)->EnableWindow(FALSE);
GetDlgItem(IDC_CLEAR1)->EnableWindow(FALSE);
GetDlgItem(IDC_READALL)->EnableWindow(FALSE);
GetDlgItem(IDC_CLEARALL)->EnableWindow(FALSE);
}
}5. Kontrol af tilslutning
Etablering af forbindelsen
Ved at indtaste Web-IO’ens IP-adresse i tekstfeltet IDC_IPTEXT og Port 80 i tekstfeltet IDC_PORTTEXT kan du bruge knappen IDC_CONNECT til at oprette en forbindelse. Hvis der ikke er indtastet en IP-adresse eller port, vises en meddelelse i statuslinjen
void CWeb_IO_ClientDlg::OnClickConnect()
{
GetDlgItemText(IDC_IPTEXT, m_ip);
GetDlgItemText(IDC_PORTTEXT, m_message2);
sscanf(m_message2, "%d", &m_port);
if(m_ip == "") {
m_statusBar->SetText("No IP entered!", 0, 0); }
else if(m_port == 0) {
m_statusBar->SetText("No port
entered!", 0, 0);
}
else {
TryConnect(); }
}Åbning af forbindelsen
For at kunne åbne en TCP-forbindelse bruger vi i vores eksempel et globalt objekt i MySocket-klassen, som indeholder metoder som Create(), Connect() og Close().
Hvis der er indtastet en negativ port, eller forbindelsen ikke kan åbnes, udsendes en tilsvarende meddelelse.
Da forbindelsen ikke kunne åbnes, lukkes stikket igen, så en ny forbindelse kan startes uden problemer.
Hvis alt gik som forventet, aktiveres alle de komponenter, der kan bruges, når forbindelsen er åbnet, og knappen IDC_CONNECT deaktiveres for at forhindre, at der åbnes en ny forbindelse, mens der allerede er en åben.
void CWeb_IO_ClientDlg::TryConnect()
{
if(m_port < 0)
{
m_statusBar->SetText("No
negative port allowed!", 0, 0);
return;
}
clientSocket.Create();
clientSocket.Connect(m_ip, m_port);
GetDlgItem(IDC_CONNECT)->EnableWindow(FALSE);
}Forbindelsen er oprettet
Hvis forbindelsen er oprettet, kan applikationen udføre kommunikation med Web-IO ved hjælp af de forskellige komponenter.
void CWeb_IO_ClientDlg::OnConnect()
{
m_statusBar->SetText("Connection made!", 0, 0);
changeAccess(TRUE);
}Frakobling
Forbindelsen forbliver åben, indtil den afsluttes ved, at brugeren klikker på knappen Afbryd forbindelsen, eller Web-IO’en afslutter forbindelsen. Hvis forbindelsen afbrydes, udsendes en meddelelse.
void CWeb_IO_ClientDlg::OnClickDisconnect()
{
OnDisconnect();
}Hvis forbindelsen afbrydes, skal alle elementer transformeres tilbage til deres oprindelige indstilling, da det ikke længere skal være muligt at klikke på knappen IDC_DISCONNECT.
void CWeb_IO_ClientDlg::OnDisconnect()
{
clientSocket.Close();
m_statusBar->SetText("Disconnected!", 0, 0);
changeAccess(FALSE);
}Nu lukkes forbindelsen igen, og applikationen nulstilles til sin oprindelige tilstand.
6. Drift og kommunikation fra klientsiden.
Så snart der er oprettet forbindelse til Web-IO, kan brugeren bruge de tilsvarende programelementer til at sende kommandoer til Web-IO.
Indstilling af udgange
Udgangene på Web-IO kan skiftes ved hjælp af de to afkrydsningsfelter IDC_OUTPUT0 og IDC_OUTPUT1. Afkrydsningsfeltet registrerer, hvornår der blev klikket på det, og udløser derefter en handling. For at kunne sende en anmodning til Web-IO’en kontrolleres det først, om der er indtastet et password i tekstfeltet IDC_PASSWORDTEXT, uden hvilket Web-IO’en ikke vil kunne acceptere nogen anmodninger. Hvis der ikke er indtastet en adgangskode, sendes anmodningen uden en adgangskode.
void CWeb_IO_ClientDlg::checkpass()
{
GetDlgItemText(IDC_PASSWORDTEXT, m_password);
}I det næste trin kontrolleres det, om afkrydsningsfeltet allerede er sat eller ej, hvorved outputtet enten nulstilles eller sættes.
void CWeb_IO_ClientDlg::OnOutput0()
{
checkpass();
m_message1 = "GET /outputaccess0?PW=" + password + "&State=ON&";
m_message2 = "GET /outputaccess0?PW=" + password + "&State=OFF&";
if(IsDlgButtonChecked(IDC_OUTPUT0))
clientSocket.Send(m_message1, m_message1.GetLength());
else
clientSocket.Send(m_message2, m_message2.GetLength());
}void CWeb_IO_ClientDlg::OnOutput1()
{
checkpass();
m_message1 = "GET /outputaccess1?PW=" + password + "&State=ON&";
m_message2 = "GET /outputaccess1?PW=" + password + "&State=OFF&";
if(IsDlgButtonChecked(IDC_OUTPUT1))
clientSocket.Send(m_message1, m_message1.GetLength());
else
clientSocket.Send(m_message2, m_message2.GetLength());
}Forespørgsel på output/input-status
Nu kan udgangs- og indgangstilstanden også kontrolleres for at opdatere kontrolboksene i programmet. Knappen IDC_READLL0 aflæser tilstanden for udgangene, og knappen IDC_READALL1 aflæser tilstanden for indgangene. Kommandoen til statusforespørgsel er lidt anderledes end den til indstilling. Du kan bruge “GET /output?PW=&” til at forespørge på status for udgangene.
void CWeb_IO_ClientDlg::OnClickReadall0()
{
checkpass();
m_message1 = "GET /output?PW=" + password + "&";
clientSocket.Send(m_message1, m_message1.GetLength());
}void CWeb_IO_ClientDlg::OnClickReadall1()
{
checkpass();
m_message1 = "GET /input?PW=" + password + "&";
clientSocket.Send(m_message1,
m_message1.GetLength());
}Forespørgselstællere
Da ankomne input-hændelser kun noteres i selve Web-IO’en og øger dens indre tæller, bør det også være muligt at forespørge på den. Den følgende metode sender en forespørgsel til en bestemt tæller og beder om et svar med tællerens aktuelle status. Fra svaret fra Web-IO’en kan nummeret på den respektive tæller og dens tælletilstand hentes og vises i applikationen.
void CWeb_IO_ClientDlg::OnClickRead0()
{
checkpass();
m_message1 = "GET /counter0?PW=" + password + "&";
clientSocket.Send(m_message1, m_message1.GetLength());
}void CWeb_IO_ClientDlg::OnClickRead1()
{
checkpass();
m_message1 = "GET /counter1?PW=" + password + "&";
clientSocket.Send(m_message1, m_message1.GetLength());
}Naturligvis kan alle tællertilstande forespørges med en enkelt kommando.
void CWeb_IO_ClientDlg::OnClickReadall()
{
checkpass();
m_message1 = "GET /counter?PW=" + password + "&";
clientSocket.Send(m_message1, m_message1.GetLength());
}Nulstil tæller
Da du kan aflæse tællerens tilstand, burde det også være muligt at sætte tælleren til 0. Til dette formål sendes en besked til den respektive tæller, som nulstiller den.
void CWeb_IO_ClientDlg::OnClickClear0()
{
checkpass();
m_message1 = "GET /counterclear0?PW=" + password + "&";
clientSocket.Send(m_message1, m_message1.GetLength());
}void CWeb_IO_ClientDlg::OnClickClear1()
{
checkpass();
m_message1 = "GET /counterclear1?PW=" + password + "&";
clientSocket.Send(m_message1, m_message1.GetLength());
}Naturligvis kan alle tællere nulstilles med en enkelt kommando.
void CWeb_IO_ClientDlg::OnClickClearall()
{
checkpass();
m_message1 = "GET /counterclear?PW=" + password + "&";
clientSocket.Send(m_message1, m_message1.GetLength());
}Da alle tællertilstande kan aflæses eller nulstilles ved hjælp af én kommando, skal der implementeres en metode, som behandler svarstrengen fra Web-IO og tildeler hver tæller i applikationen dens specifikke tilstand.
void CWeb_IO_ClientDlg::readAndClearCounter(CString data)
{
int j = 0;
CString counter[12];
for(int i = 0; i < data.GetLength(); i++)
{
if(data[i] == ';')
j++;
else
counter[j]+= data[i];
}
SetDlgItemText(IDC_COUNTERTEXT0, counter[0]);
SetDlgItemText(IDC_COUNTERTEXT1, counter[1]);
}7. Modtagelse af data fra Web-IO
Behandle og vise de modtagne data
- Alle kommandoer og anmodninger til Web-IO kvitteres med en svarstreng. Svarene har en bestemt struktur afhængigt af typen.
- Der skelnes mellem svaret fra en enkelt udgang eller indgang og en afspilning fra alle udgange og indgange.
- For udgangene: output;<binær værdi af udgangsstatus i hexadecimalt format>
- For en særlig udgang: outputx;<ON eller OFF>
- For indgangene: input;<binær værdi af indgangsstatus i hexadecimalt format>
- For et særligt input inputx;<ON eller OFF>
- Der er også en svarstreng for en tæller, som ser således ud:
counterx;<decimal counter state>
eller counter;<decimal counter state 0 >; <decimal counter state 1 >; … hvis du vil aflæse alle tællerne på én gang.
Alle svarstrenge afsluttes med en 0-byte. - I vores program påkaldes metoden OnReceiver() for at modtage en sådan besked. I denne metode behandles svaret fra Web-IO’en.
void CWeb_IO_ClientDlg::OnReceive()
{
clientSocket.Receive(m_rcv.GetBuffer(50),50);
m_rcv.ReleaseBuffer();
if(m_rcv.IsEmpty())
OnDisconnect();
else if(m_rcv.GetLength() > 1)
{
if(m_rcv[0] == 'o')
{
int i;
sscanf(m_rcv.Right(m_rcv.GetLength() - 7), "%x", &i);
if((i & 1) == 1) CheckDlgButton(IDC_OUTPUT0, BST_CHECKED);
else CheckDlgButton(IDC_OUTPUT0, BST_UNCHECKED);
if((i & 2) == 2) CheckDlgButton(IDC_OUTPUT1, BST_CHECKED);
else CheckDlgButton(IDC_OUTPUT0, BST_UNCHECKED);
}
if(m_rcv[0] == 'i')
{
int i;
sscanf(m_rcv.Right(m_rcv.GetLength() - 6), "%x", &i);
if((i & 1) == 1) CheckDlgButton(IDC_INPUT0, BST_CHECKED);
else CheckDlgButton(IDC_INPUT0, BST_UNCHECKED);
if((i & 2) == 2) CheckDlgButton(IDC_INPUT1, BST_CHECKED);
else CheckDlgButton(IDC_INPUT1, BST_UNCHECKED);
}
if(m_rcv[0] == 'c')
{
if(m_rcv[7] == '0')
SetDlgItemText(IDC_COUNTERTEXT0, m_rcv.Right(m_rcv.GetLength() - 9));
if(m_rcv[7] == '1')
SetDlgItemText(IDC_COUNTERTEXT1, m_rcv.Right(m_rcv.GetLength() - 9));
if(m_rcv[7] == ';')
readAndClearCounter(m_rcv.Right(m_rcv.GetLength() - 8));
}
}
}8. Afstemning
Cyklisk polling af bestemte værdier
Nu er det ønskeligt, at de enkelte komponenter selv opdaterer deres status, så applikationen altid viser den seneste status. Til det formål bruger programmet en timer, som sender cykliske forespørgsler til Web-IO med et brugerdefineret tidsinterval.
Først kan der indtastes en heltalsværdi i feltet IDC_POLLINGTEXT, som definerer tiden i millisekunder for den cykliske forespørgsel. Hvis der ikke indtastes nogen værdi, indstilles tiden for intervallet til standard 1 sekund (1000 ms).
Dette fanger selvfølgelig også tilfælde, hvor brugeren indtaster en nonsensværdi, såsom en negativ tidsværdi. Dette efterfølges straks af en besked, og værdien anvendes ikke.
void CWeb_IO_ClientDlg::OnChangePollingtext()
{
GetDlgItemText(IDC_POLLINGTEXT, m_message2);
int check;
sscanf(m_message2, "%d", &check);
if(check <= 0)
{
m_statusBar->SetText("No negative
value or character allowed!", 0, 0);
return;
}
m_range = check;
m_statusBar->SetText("Range
changed!", 0, 0);
}For nu at udføre cyklisk polling af Web-IO-tilstande kan man vælge mellem polling af udgangene, indgangene eller tællerne.
For hver polling-variant initialiseres en timer. Timeren påkaldes med “SetTimer(timer number, interval, NULL)”.
Hvis du aktiverer afkrydsningsfeltet IDC_POLLING0, betyder det, at udgangene polles. En timer initialiseres, hvis den er blevet indstillet. Hvis afkrydsningsfeltet deaktiveres igen, slettes timeren med det tilsvarende nummer.
void CWeb_IO_ClientDlg::OnPolling0()
{
if(IsDlgButtonChecked(IDC_POLLING0))
SetTimer(1, m_range, NULL);
else
KillTimer(1);
}Hvis du klikker på afkrydsningsfeltet IDC_POLLING1, vil indgangene blive pollet. En ny timer initialiseres, som kan slettes igen ved hjælp af denne metode.
void CWeb_IO_ClientDlg::OnPolling1()
{
if(IsDlgButtonChecked(IDC_POLLING1))
SetTimer(2, m_range, NULL);
else
KillTimer(2);
}Hvis du også vil forespørge tællerne ved hjælp af polling, kan du bruge afkrydsningsfeltet IDC_POLLINGCOUNTER.
void CWeb_IO_ClientDlg::OnPollingcounter()
{
if(IsDlgButtonChecked(IDC_POLLINGCOUNTER))
SetTimer(3,m_range, NULL);
else
KillTimer(3);
}Tre forskellige timere blev initialiseret, som udløser en handling med bestemte tidsintervaller afhængigt af indstillingen, som indtil nu ikke er registreret. Der mangler stadig at blive implementeret en metode til at opfange begivenhederne.
I denne metode indfanges den respektive hændelse i den timer, der rapporterer i øjeblikket, og tildeles en bestemt handling.
Husk på det: I vores tilfælde polles udgangene, indgangene og tællernes tilstande cyklisk afhængigt af hændelsen.
void CWeb_IO_ClientDlg::OnTimer(UINT nIDEvent)
{
if(nIDEvent == 1) OnClickReadall0();
if(nIDEvent == 2) OnClickReadall1();
if(nIDEvent == 3) OnClickReadall();
CDialog::OnTimer(nIDEvent);
}Hele programmet er tilgængeligt på denne side, og det indeholder nogle filer og metoder, som ikke er nævnt her. MFC-applikationen under Visual C++ genererer et overhead, som danner den grafiske ramme, men som ikke er direkte forbundet med funktionaliteten. De metoder og variabler, du får vist på denne side, er implementeret i de rammer, der genereres af Visual C++, og fungerer derefter som en enhed med den grafiske grænseflade.
Eksempelprogrammet understøtter alle almindelige funktioner i Web-IO i kommandostrengstilstand, optimeret til Web-IO 2x Digital Input, 2x Digital Output PoE. For de andre Web-IO-modeller kan det være nødvendigt at tilpasse programmet. Yderligere programeksempler til socket-programmering kan findes på værktøjssiderne for Web-IO. En detaljeret beskrivelse af socket-grænsefladen til Web-IO Digital-modellerne findes i referencemanualen.
Wiesemann & Theis GmbH blev grundlagt i 1979 af Reinhard Wiesemann og Rüdiger Theis. Med 50 ansatte producerer virksomheden mikrocomputer- og netværksteknologi i Wuppertal. I 2001 introducerede Wiesemann & Theis den første industrielle temperatursensor med et netværksinterface, Web-Thermometer, og har næsten 20 års erfaring inden for områderne Industri 4.0 og Internet of Things.
Active Communication har været distributør for W&T siden 1992 i Danmark og siden 2002 også i Sverige, Norge og Island. W&T’s produkter er ekstremt brugervenlige og pålidelige til en konkurrencedygtig pris.