Hlavní navigace

Sériový port v Chrome

14. 11. 2013 21:01 Petr Blahoš

Píšu aplikaci, která přečte HID kartu (sériová čtečka), potom změří antistatiku (měřák připojený přes sériový port), výsledek zapíše na server k majiteli oné HID karty, a pak ještě případně povolí nebo zakáže nějaké činnosti, podle toho, jestli ten člověk prošel antistatikou. Těšil jsem se, že to bude všechno ve webovém browseru, protože ač mám javascript nerad, tak kombinaci html+js se nedá upřít, že jednoduchá uživatelská rozhraní se v ní dělají dobře. Navíc bych získal výhodu, že by kód byl na serveru, a já bych nikdy nemusel vydávat novou verzi. Tento článek popisuje, jak to šlo, a proč jsem toho nakonec nechal, a udělal to v zaběhnutém wxPythonu.

Když mluvíme o aplikacích pro Chrome, dá se rozlišovat mezi:

  • Extensions – rozšíření prohlížeče, které nějak obohacují funkci prohlížeče
  • Packaged Apps – aplikace, které nejsou rozšíření, ale jejich kód je instalován do prohlížeče
  • Hosted Apps – vpodstatě odkazy na webové stránky, kterým lze přidat nějaká oprávnění

Packaged Apps jsou jediné, které umožňují použít serial api (a taky např. usb api a socket api). Packaged Apps je také ten mechanizmus, o kterém se nedávno dost psalo, který umožní udělat aplikaci, která poběží ve zvláštním okně bez omniboxu, menu, ovládacích tlačítek, prostě aplikačním okně. Se sériovým portem to pak funguje tak, jak bychom asi očekávali. Aplikaci povolíme chrome.serial a přístup na nějakou webovou stránku (např. na naši intranetovou aplikaci). Zjistíme si, jaké má počítač sériové porty, případně z nastavení přečteme který, nebo které máme použít, a můžeme z nich vesele číst. Bohužel, to API je takové tupé. Zatímco v nějakém normálním prostředí bychom měli blokující čekání na data v druhém threadu, nebo bychom dělali polling, chrome.serial.read neblokuje, takže se dá dělat:

function onRead(readInfo) {
  if (readInfo.bytesRead) {
    var s = String.fromCharCode.apply(null, new Uint8Array(readInfo.data));
    // ...
  }
  chrome.serial.read(connectionId, 20, onRead);
};

jenže to nám vytíží procesor. Takže uděláme:

function onRead(readInfo) {
  if (readInfo.bytesRead) {
    var s = String.fromCharCode.apply(null, new Uint8Array(readInfo.data));
    // ...
  }
  setTimeout(function() { chrome.serial.read(connectionId, 20, onRead); }, 10);
};
což už procesor vytíží minimálně, na ten sériový port to stačí, ale přece jen je to tupé, a musím se ptát, proč zrovna 10ms. Data přečtená ze sériového portu můžu (potom co si ověřím, že jsou celá) třeba poslat své intranetové aplikaci.

Aplikace, kterou jsem si napsal na vyzkoušení, je tak jednoduchá, že ji ani nebudu zveřejňovat (ledaže si o ni někdo ozve). Místo toho dva odkazy:

Proč jsem toho nakonec nechal a vrátil se k wxPython? Mám dva důvody. Jeden je ten, že jsem v té době četl, že rozšíření půjdou instalovat jen z Chrome Web Store. Nevím, jestli se to týká i aplikací. Pokud ne, nevím, jestli se to zítra nezačne týkat i aplikací. Nevadilo by mi dát tu aplikaci googlu. Řekněme si upřímně, aplikaci, která něco přečte ze sériového portu, pošle to na server a na základě odpovědi něco zobrazí, dokáže napsat kdekdo. Jenže já nemám jistotu, že počítač, na kterém ta věc poběží se vůbec dostane na internet. Druhý důvod je ten, že jsem vlastně původně myslel na hosted application – tedy do webového prohlížeče se instaluje jenom manifest, vše ostatní je na serveru, a já se nemusím starat o tvorbu balíčků s novou verzí (a případnou distribuci přes chrome web store).

Sdílet