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:

Konzole ve webové stránce

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).

<%@ Page Language=“C#“ Trace=“False“ Debug=“False“ %>
<%@ 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:

 Int32 deviceCommPort = Int32.Parse(ConfigurationSettings.AppSettings[„DeviceCommPort“]);
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:

<appSettings>
  <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).

void Port_IsClosed()
{
  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í.

void Port_IsOpen()
{
  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.

void Turn_On(object sender, System.EventArgs e)
{
  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().

void Turn_Off(object sender, System.EventArgs e)
{
  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().

void Read_Input(object sender, System.EventArgs e)
{
  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().

void Set_Output(object sender, System.EventArgs e)
{
  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:

<authentication mode=“Forms“>
  <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:

csc.exe /t:library /r:RS232.dll Default.aspx.cs

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).

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět