Komunikujeme p°es sΘriovΘ rozhranφ v ASP.NET podruhΘ
Pomocφ .NET m∙₧eme snadno vytvo°it °adu zajφmav²ch aplikacφ komunikujφcφch p°es rozhranφ systΘmu. V tomto Φlßnku si ukß₧eme, jak vytvo°it jednoduchou ovlßdacφ konzoli, pomocφ nφ₧ m∙₧eme prost°ednictvφm internetu nap°φklad zapnout osv∞tlenφ ve vzdßlenΘ budov∞ nebo zjistit, zda n∞kdo nevstoupil do hlφdan²ch prostor.
V p°edchozφm Φlßnku Komunikujeme p°es sΘriovΘ rozhranφ v ASP.NET jsme nevy°eÜili problΘm s ulo₧enφm objektu aktußln∞ otev°enΘho portu za°φzenφ, mohli jsme tedy pouze ze za°φzenφ naΦφst aktußlnφ stav a port zav°φt. V tomto Φlßnku umo₧nφme za°φzenφ i ovlßdat - objekt portu za°φzenφ si ulo₧φme do Application.
Zßkladem aplikace je webov² formulß° s webov²mi ovlßdacφmi prvky, jak vidφme i z obrßzku:
Pro jednoduchΘ Φtenφ stav∙ vypnuto a zapnuto m∙₧eme pou₧φt celkem Φty°i linky (CTS, DSR, DCD, RI) a pro zßpis (nastavenφ) dva v²stupy (DTR, RTS), p°φpadn∞ jeÜt∞ v²stup TxD p°i nastavenφ stavu Break (popφÜeme si dßle).
<%@ Import Namespace="System.Web.Security" %>
<%@ Assembly Name="RS232" %>
<form runat="server">
<fieldset style="width:480px; padding:12px;">
<legend>Device on COM<asp:Literal Id="ltrDevId" RunAt="server" /></legend>
<div style="clear:all;">
<asp:Label Id="lblError" Font-Bold="true" RunAt="server" />
</div>
<fieldset style="width:240px; clear:none; padding:12px;">
<legend>Input Status</legend>
<asp:CheckBox id="chkCts" Enabled="False" runat="server" Text="CTS" />
<asp:CheckBox id="chkDsr" Enabled="False" runat="server" Text="DSR" />
<asp:CheckBox id="chkDcd" Enabled="False" runat="server" Text="DCD" />
<asp:CheckBox id="chkRi" Enabled="False" runat="server" Text="RI" />
<br /><br />
<asp:Button Id="btnReadIn" OnClick="Read_Input" runat="server" Text="Read input" />
</fieldset>
<fieldset style="width:200px; clear:none; padding:12px;">
<legend>Output Control<br /></legend>
<asp:CheckBox id="chkDtr" AutoPostBack="true" OnCheckedChanged="Set_Output" runat="server" Text="DTR" />
<asp:CheckBox id="chkRts" AutoPostBack="true" OnCheckedChanged="Set_Output" runat="server" Text="RTS" />
<asp:CheckBox id="chkBrk" AutoPostBack="true" OnCheckedChanged="Set_Output" runat="server" Text="BRK" />
<br /><br />
<asp:Button Id="btnSetOut" OnClick="Set_Output" runat="server" Text="Set output" />
</fieldset>
<br /><br />
<asp:Button Id="btnTurnOff" OnClick="Turn_Off" runat="server" Text="Turn Off" />
<asp:Button Id="btnTurnOn" OnClick="Turn_On" runat="server" Text="Turn On" />
<asp:Button Text="Logout" OnClick="Logout" RunAt="server" />
</fieldset>
</form>
Ve formulß°i mßme CheckBoxy, kterΘ nejen umo₧≥ujφ pohodlnΘ nastavenφ, ale zßrove≥ ukazujφ aktußlnφ stav. Prvnφ Φty°i jsou v re₧imu, kdy jsou zakßzanΘ - slou₧φ pouze jako indikßtor stavu, nelze na n∞ kliknout. DalÜφ t°i slou₧φ k indikaci i k ovlßdßnφ. Dßle mßme k dispozici tlaΦφtka Button pro odeslßnφ formulß°e - naΦtenφ dat Read input
, vystavenφ dat Set output
, zapnutφ Turn On
a vypnutφ za°φzenφ Turn Off
a tlaΦφtko pro odhlßÜenφ Logout
. Nastavovacφ CheckBoxy
majφ zapnut² AutoPostBack, tak₧e pokud klient podporuje JavaScript, dochßzφ k nastavovßnφ za°φzenφ p°φmo, formulß° se odesφlß samoΦinn∞. Prvek Label slou₧φ k zobrazovßnφ stavu za°φzenφ nebo chybov²ch zprßv.
Dßle si popφÜeme obslu₧nou Φßst se vÜemi pot°ebn²mi metodami:
CMediaRs232 moRS232 = new CMediaRs232();
void Page_Load(object sender, System.EventArgs e)
{
ltrDevId.Text = deviceCommPort.ToString();
if (!IsPostBack)
{
moRS232 = (CMediaRs232) Application["myPort"];
if (Application["myPort"] != null)
{
moRS232 = (CMediaRs232) Application["myPort"];
if (moRS232.IsOpen)
Port_IsOpen();
else
Port_IsClosed();
}
else
Port_IsClosed();
}
}
void Logout(Object sender, EventArgs E)
{
FormsAuthentication.SignOut();
Response.Redirect("Login.aspx",true);
}
Nastavenφ Φφsla portu za°φzenφ v konfiguraΦnφm souboru:
<add key="DeviceCommPort" value="2" />
</appSettings>
V Page_Load
zobrazφme Φφslo portu, na kterΘm je p°ipojeno ovlßdanΘ za°φzenφ (hodnotu mßm p°ipravenou p°edem z Web.configu). Pokud nenφ formulß° odeslßn (jednß se o prvnφ naΦtenφ strßnky), provedeme pokus o zφskßnφ objektu ovlßdanΘho za°φzenφ z Application
. Pokud se nßm poda°φ objekt zφskat (objekt nenφ null
), pak se dotß₧eme, zda je port otev°en. Pokud ano, provedeme obslu₧nou metodu Port_IsOpen()
, jinak provedeme Port_IsClosed()
. TutΘ₧ metodu provedeme v p°φpad∞, ₧e se nßm nepoda°ilo objekt zφskat (za°φzenφ pravd∞podobn∞ doposud nikdo neovlßdal nebo prßci s nφm korektn∞ ukonΦil).
{
chkCts.Checked = false;
chkDsr.Checked = false;
chkDcd.Checked = false;
chkRi.Checked = false;
chkDtr.Checked = false;
chkDtr.Enabled = false;
chkRts.Checked = false;
chkRts.Enabled = false;
chkBrk.Checked = false;
chkBrk.Enabled = false;
btnReadIn.Enabled = false;
btnSetOut.Enabled = false;
btnTurnOff.Visible = false;
btnTurnOn.Visible = true;
lblError.Text = "Device is turned off.";
}
Metoda Port_IsClosed()
jednoduÜe p°ipravφ formulß° do stavu, kdy za°φzenφ nenφ ovlßdßno a naÜe aplikace se o n∞j "nezajφmß". Zatrhßvacφ polφΦka jsou odÜkrtnuta a zakßzßna, je skryto tlaΦφtko pro vypnutφ za°φzenφ a zviditeln∞no tlaΦφtko pro zapnutφ za°φzenφ. Nakonec nastavφme text hlßÜenφ informujφcφho o vypnutφ za°φzenφ.
{
chkDtr.Enabled = true;
chkRts.Enabled = true;
chkBrk.Enabled = true;
btnReadIn.Enabled = true;
btnSetOut.Enabled = true;
btnTurnOff.Visible = true;
btnTurnOn.Visible = false;
if (Application["myDtr"] != null)
chkDtr.Checked = (Boolean) Application["myDtr"];
else
moRS232.Dtr = false;
if (Application["myRts"] != null)
chkRts.Checked = (Boolean) Application["myRts"];
else
moRS232.Rts = false;
if (Application["myBreak"] != null)
chkBrk.Checked = (Boolean) Application["myBreak"];
else
moRS232.Break = false;
lblError.Text = "Device is turned on.";
}
V metod∞ Port_IsOpen()
p°ipravujeme formulß° pro p°φpad, ₧e za°φzenφ je zapnutΘ a naÜe aplikace nad nφm tedy mß kontrolu. Povolφme ovlßdacφ zatrhßvacφ polφΦka, skryjeme tlaΦφtko pro zapnutφ a zviditelnφme tlaΦφtko pro vypnutφ. Dßle z Application
obnovφme ve formulß°i zobrazovan² stav v²stupnφch linek DTR, RTS a stav BREAK. Hodnoty je mo₧nΘ do za°φzenφ pouze zapisovat a tak si je musφme ulo₧it souΦasn∞ i do Application
, abychom byli schopni ve formulß°i zobrazit stav za°φzenφ, kter² byl nastaven d°φve (t°eba jin²m u₧ivatelem z ·pln∞ jinΘho poΦφtaΦe). Text hlßÜenφ nastavφme na text informujφcφ o tom, ₧e za°φzenφ je zapnuto - mßme ho pod kontrolou.
{
if (Application["myPort"] == null)
{
moRS232.Port = deviceCommPort; // COM1
moRS232.BaudRate = 2400; // 2400 baud rate
moRS232.DataBit = 8; // 8 data bits
moRS232.StopBit = CMediaRs232.DataStopBit.StopBit_1; // 1 Stop bit
moRS232.Parity = CMediaRs232.DataParity.Parity_None; // No Parity
moRS232.Timeout = 500; // 500 ms
try
{
moRS232.Open();
Application["myPort"] = moRS232;
Port_IsOpen();
}
catch (Exception eX)
{
lblError.Text = "Error control serial port - try restart IIS";
btnReadIn.Enabled = false;
btnSetOut.Enabled = false;
}
}
else
{
moRS232 = (CMediaRs232) Application["myPort"];
if (moRS232.IsOpen)
Port_IsOpen();
else
Port_IsClosed();
}
}
Metoda Turn_On()
je obsluha stisknutφ "zapφnacφho" tlaΦφtka. Pokud objekt za°φzenφ v Application
je null
(za°φzenφ nenφ pod kontrolou), nastavφme novΘ hodnoty objektu pro prßci se za°φzenφm, pokusφme se otev°φt port, objekt ulo₧φme do Application
a zavolßnφm metody Port_IsOpen()
"p°edp°ipravφme" formulß°. Pokud se nepoda°φ otev°φt port (dojde k v²jimce), nastavφme text hlßÜenφ informujφcφ o chyb∞ (m∙₧eme i doporuΦit restart IIS) a zakß₧eme ovlßdacφ tlaΦφtka pro Φtenφ a nastavovßnφ za°φzenφ. Pokud objekt za°φzenφ v Application
p°φtomen je, pak se prost∞ dotß₧eme, zda je port otev°en. Pokud je port otev°en, p°edp°ipravφme formulß° metodou Port_IsOpen()
, v opaΦnΘm p°φpad∞ bude formulß° nastaven pro vypnut² stav za°φzenφ metodou Port_IsClosed()
.
{
if (Application["myPort"] != null)
{
moRS232 = (CMediaRs232) Application["myPort"];
if (moRS232.IsOpen)
{
moRS232.Close();
Application["myPort"] = null;
Application["myDtr"] = null;
Application["myRts"] = null;
Application["myBreak"] = null;
}
}
Port_IsClosed();
}
TlaΦφtko pro vypnutφ za°φzenφ je obsluhovßno metodou Turn_Off()
. Pokud se poda°φ z aplikace zφskat objekt za°φzenφ a port za°φzenφ je otev°en, pak port za°φzenφ uzav°eme a hodnoty ulo₧enΘ do Application
"pouklφzφme" nastavenφm na null
. Mo₧nß by se pat°ilo "pouklφzet" i naÜe klφΦe myPort
, myDtr
, myRts
a myBreak
- "zahodit je" metodou Application.Remove(), jß vÜak p°edpoklßdßm, ₧e tento typ aplikace pob∞₧φ jako vyhrazenß virtußlnφ aplikace, tak₧e by nßm v nφ stejn∞ vznikaly a zanikaly stßle tytΘ₧ klφΦe. Nakonec pak v₧dy provedeme nastavenφ formulß°e do vypnutΘho stavu pomocφ Port_IsClosed()
.
{
if (Application["myPort"] != null)
{
moRS232 = (CMediaRs232) Application["myPort"];
if (moRS232.IsOpen)
{
chkCts.Checked = moRS232.Cts;
chkDsr.Checked = moRS232.Dsr;
chkDcd.Checked = moRS232.Dcd;
chkRi.Checked = moRS232.Ri;
}
else
Port_IsClosed();
}
else
Port_IsClosed();
}
NaΦtenφ stavu za°φzenφ obsluhuje metoda Read_Input()
. Pokud objekt za°φzenφ je dostupn², otestujeme, zda je port otev°en². Pokud ano, nastavφme zatrhßvacφ polφΦka ve formulß°i na hodnoty linek CTS, DSR, DCD a RI. Pokud nenφ port otev°en² nebo objekt za°φzenφ nenφ dostupn², prost∞ formulß° p°enastavφme do vypnutΘho stavu metodou Port_IsClosed()
.
{
if (Application["myPort"] != null)
{
moRS232 = (CMediaRs232) Application["myPort"];
if (moRS232.IsOpen)
{
moRS232.Dtr = chkDtr.Checked;
Application["myDtr"] = chkDtr.Checked;
moRS232.Rts = chkRts.Checked;
Application["myRts"] = chkRts.Checked;
moRS232.Break = chkBrk.Checked;
Application["myBreak"] = chkBrk.Checked;
Read_Input(sender,e);
}
else
Port_IsClosed();
}
else
Port_IsClosed();
}
Metoda Set_Output()
je volßna nejen tlaΦφtkem, ale takΘ automaticky p°i kliknutφ na nastavovacφ zatrhßvacφ polφΦka (majφ nastaveno AutoPostback = true
). Pokud je objekt za°φzenφ dostupn², ov∞°φme, je-li port otev°en. Pokud ano, nastavφme podle stavu zatrhßvacφch polφΦek v²stupnφ linky DTR, RTS nebo aktivujeme stav BREAK. SouΦasn∞ si nastavenφ uklßdßme do Application
, aby bylo pozd∞ji dostupnΘ v Port_IsOpen()
. Nakonec jeÜt∞ provedeme obΦerstvenφ indikace vstupnφch linek zavolßnφm metody Read_Input()
. Pokud nenφ port otev°en, nebo nenφ v∙bec dostupn² objekt za°φzenφ, volßme Port_IsClosed()
, tak₧e formulß° bude nadßle zobrazovat stav, kdy za°φzenφ je vypnuto.
P°φstup k aplikaci ochrßnφme prost°ednictvφm Forms autentizace nastavenφm ve Web.config:
<forms name="AuthCookie" loginUrl="Login.aspx" protection="All" timeout="30" path="/">
<credentials passwordFormat="Clear">
<user name="houba" password="autobus" />
<user name="strom" password="tramvaj" />
</credentials>
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
NaÜe aplikace je spφÜe jen ukßzkou pro demonstraci, nic vÜak nebrßnφ jejφmu pou₧itφ pro skuteΦn² provoz. Pro reßlnΘ nasazenφ by bylo dobrΘ nejen upravit formulß° (aby byl u₧ivatelsky p°φv∞tiv²), ale do°eÜit i souΦasn² provoz za°φzenφ na vφce portech - v naÜφ ukßzce je vyu₧φvßn jedin² klφΦ portu p°i prßci s Application
, ovlßdat tedy na jednom stroji v jednΘ virtußlnφ aplikaci souΦasn∞ vφce za°φzenφ na r∙zn²ch portech je nemo₧nΘ. Pokud bychom po₧adovali Φast∞jÜφ naΦφtßnφ stavu za°φzenφ, m∙₧eme do strßnky doplnit autorefresh.
Pokud nepracujete ve Visual Studiu, hodilo by se p°epsat Φßst skriptu do CodeBehind a tento zkompilovat do knihovny. Mimo jin²ch v²hod uspφÜφme i start aplikace po restartu slu₧eb IIS, proto₧e hlavnφ Φßst aplikace bude ji₧ zkompilovanß. Knihovnu potΘ ulo₧te do adresß°e Bin v ko°eni virtußlnφ aplikace na serveru a nezapome≥te odebrat ve strßnce z direktivy @Page atribut Src, jinak dojde k chyb∞ duplicitnφ definice t°φd naÜeho Codebehindu
. Pro kompilaci je pot°eba p°idat referenci na knihovnu RS232, nap°φklad takto:
Server pro aplikaci by m∞l b²t rad∞ji vyhrazen², aby p°φpadnß kolize naÜφ aplikace neohrozila b∞h jin²ch aplikacφ. Nenφ ani pot°eba extrΘmnφ v²kon, staΦφ b∞₧nΘ PC, na kterΘm rozb∞hnete IIS, v krajnφm p°φpad∞ by mohl postaΦit i testovacφ server Cassini.
Ukßzkovou aplikaci vΦetn∞ knihovny RS232.dll si m∙₧ete stßhnout (zdrojov² k≤d).