Jak psát sériový komunikační driver v Merbon RT

Programování v jazyce ST (strukturovaný text) nabízí autorům aplikací značnou flexibilitu. Jednou z často poptávaných vlastností je vývoj komunikačních driverů pro cizí systémy. Na následujícím příkladu (ke stažení jako projekt Merbon IDE zde) si ukážeme, jak vypadá „zákaznický“ driver pro elektroměry Pozyton sEAB.

Tyto elektroměry komunikují po sériové lince. Protokol vychází z normy IEC 62056-21, mírně se však liší, a proto bylo nutné napsat pro vyčítání dat zvláštní funkci. Popis komunikace je v dokumentu na webu Pozyton: www.pozyton.com.pl/polskiepdf/protokoly/ptd_sea-b.pdf.

Komunikace je stavově řízená a její možné stavy vidíme v komentáři ke kódu – blok Pozyton_seaB, ř. 270 a dále:

// Communication states:
// 0 - Initialisation
// 1 - Write ID
// 2 - Communication status
// 3 - Readout
// 4 - Writing HELLO
// 5 - Communication status
// 6 - Reading (ID)
// 7 - Writing command for data
// 8 - Communication status + waiting
// 9 - Closing of the port (obsolete)
// 10 - Waiting (5s)
// 11 - Communication status (obsolete)
// 12 - Data reading
// 13 - Closing of the port
// 14 - Finishing of communication
// 15 - Stand By - waiting for the next communication window

Krok 0 inicializuje komunikační port, krok 1 zapisuje dotaz ve tvaru

/Attt.nnnnnnn[CR][LF]

kde ttt.nnnnnnn je sériové číslo měřiče. (Všechny měřiče odpovídají také na sériové číslo 000.0000000, což lze využít v případech, že na sběrnici je pouze jeden elektroměr.)

V kroku 2 se čeká na odeslání dotazu, v kroku 3 následuje příjem odpovědi. Odpověď měřiče vypadá takto:

/gttt.nnnnnnn[CR][LF]

Následuje krok 4, což je standardní příkaz podle normy IEC 62056-21, tedy sekvence

/?![CR][LF]. Na ni je v kroku 6 přijímána odpověď, u níž se pouze kontroluje, zda obsahuje jako poslední ukončovací znaky[CR][LF]. Poté následuje krok 7, v němž jsou poptávána data podle dokumentace Pozyton příkazem pro přechod do módu vysílání hodnot

[ACK]054[CR][LF]

a program v kroku 8 čeká na odeslání dat, načež v kroku 10 čeká 5 sekund, než se v kroku 12 pustí do zpracování přijatých dat. Rozebrání příchozího řetězce neboli parsování je úkol pro funkci parseData, která v řetězci identifikuje sekvence podle OBIS kódů (jak jsou popsány v normě IEC 62056-21) ve tvaru

y.8.0.(eeeeee.ee)[CR][LF]

kde y je parametr, který určuje, o jaký typ energie se jedná:

y energie
0 P+ (činná spotřeba)
1 P- (činná výroba)
2 Q+ (jalová spotřeba)
3 Q- (jalová výroba)

„eeeeee.ee“ je hodnota, která nás zajímá, a „0“ na třetí pozici znamená, že jde o součet energií ve všech 3 fázích (toto zjistíme v popisu komunikace k elektroměru Pozyton).

Postup rozebírání příchozího řetězce na jednotlivé hodnoty je vidět ve smyčce, začínající na ř. 472 kódu:

while (received > 1) do
received := last_received - parseData(dataLen:=last_received,
a => a, b => b, c => c, d => d, value => val);
// End of communication - parsing was not executed - no data available
if (received = last_received) then
exit;
end_if;
// 0.8.0
if (a = 0 and b = 8 and c = 0 and d < 0) then
actual_energy_p_plus := val;
end_if;
// 1.8.0
if (a = 1 and b = 8 and c = 0 and d < 0) then
actual_energy_p_minus := val;
end_if;
// 2.8.0
if (a = 2 and b = 8 and c = 0 and d < 0) then
actual_energy_q_plus := val;
end_if;
//3.8.0
if (a = 3 and b = 8 and c = 0 and d < 0) then
actual_energy_q_minus := val;
end_if;
last_received := received
end_while;

Proměnná d by nabývala nulové nebo vyšší hodnoty pokud by identifikátor proměnné byl ve tvaru y.8.0.x. Takový identifikátor by nevyhovoval pravidlu pro hodnoty, jež chceme vyčítat, a příslušné proměnné by vyčtená hodnota val nebyla přiřazena. Nakonec, v krocích 13 až 15, se uzavírá port a čeká na další komunikační cyklus.

Podrobnější popis jednotlivých kroků je v komentářích v kódu.

pozyton_blok

Funkce je v příkladu psána v podobě funkčního bloku, jehož vstupy (komunikační port, interval odečtu, sériové číslo měřiče) jsou nastaveny jako konstanty – v průběhu vykonávání programu se nebudou měnit. Na výstupech bloku jsou nakomunikované hodnoty. Další proměnné, jako comm_error, tout a write_block se používají pro detekci chyb a vzájemné blokování komunikace mezi bloky pro případ, že by na sériové lince bylo více měřičů.