Napišite program za com port. Preusmjeravanje podataka sa COM porta na Web

Programeri vole serijske portove zbog njihove lakoće održavanja i upotrebe.

I naravno, pisanje u konzolu terminalskog programa je sve u redu, ali ja želim svoju aplikaciju koja pritiskom na tipku na ekranu izvodi radnje koje su vam potrebne;)

U ovom članku ću opisati kako raditi sa com portom u C++ jeziku.

Rješenje je jednostavno, ali iz nekog razloga radni primjer nije pronađen odmah. Za simu čuvam ga ovdje.

Naravno, možete koristiti višeplatformska rješenja kao što je QSerial - biblioteka u Qt-u, vjerovatno ću, ali u budućnosti. Sada govorimo o "čistim" Windowsima C++. Pisaćemo vizuelni studio. Imam 2010, mada ovo ne igra nikakvu ulogu...

Kreirajte novi konzolni Win32 projekat.

Uključite fajlove zaglavlja:

#include #include korištenje imenskog prostora std;

Deklarišemo rukovaoca com portom:

HANDLE hSerial;

Radim to globalno tako da ne moram da brinem o pokazivačima kada ga prosleđujem funkcijama.

int _tmain(int argc, _TCHAR* argv) (

Ne podnosim Windows stil programiranja. Sve su zvali na svoj način i sede se radujući se...

Sada je magija deklarisanja stringa sa imenom porta. Stvar je u tome što nije u stanju da transformiše sam char.

LPCTSTR sPortName = L"COM1";

Rad sa serijskim portovima u Windows-u radi kao sa fajlom. Otvaranje prvog com port za pisanje/čitanje:

HSerial = ::CreateFile(sPortName,GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

Provjera funkcionalnosti:

If(hSerial==INVALID_HANDLE_VALUE) ( if(GetLastError()==ERROR_FILE_NOT_FOUND) ( cout<< "serial port does not exist.\n"; } cout << "some other error occurred.\n"; }

Sada morate konfigurirati parametre veze:

DCB dcbSerialParams = (0); dcbSerialParams.DCBlength=sizeof(dcbSerialParams); if (!GetCommState(hSerial, &dcbSerialParams)) ( cout<< "getting state error\n"; } dcbSerialParams.BaudRate=CBR_9600; dcbSerialParams.ByteSize=8; dcbSerialParams.StopBits=ONESTOPBIT; dcbSerialParams.Parity=NOPARITY; if(!SetCommState(hSerial, &dcbSerialParams)) { cout << "error setting serial port state\n"; }

Na msdn-u se savjetuje da prvo dobijete parametre, a zatim ih promijenite. Još uvijek učimo, pa radimo po želji.

Sada deklarirajmo string koji ćemo proslijediti i varijable potrebne za to:

Char data = "Pozdrav iz C++"; // string za prosljeđivanje DWORD dwSize = sizeof(data); // veličina ovog niza DWORD dwBytesWritten; // ovdje će biti broj bajtova koji su stvarno preneseni

Slanje niza. Da vas podsjetim da je primjer najjednostavniji, tako da ne radim nikakve posebne provjere:

BOOL iRet = WriteFile(hSerial,data,dwSize,&dwBytesWritten,NULL);

Također sam odlučio prikazati veličinu stringa i broj bajtova koji se šalju u kontrolu:

Cout<< dwSize << " Bytes in string. " << dwBytesWritten << " Bytes sended. " << endl;

Na kraju programa pravimo beskonačnu petlju čitanja podataka:

Dok(1) ( ReadCOM(); ) return 0; )

Sada funkcija čitanja:

Void ReadCOM() ( DWORD iSize; char sReceivedChar; while (true) ( ​​ReadFile(hSerial, &sReceivedChar, 1, &iSize, 0); // dobiti 1 bajt ako (iSize > 0) // ispisati cout ako je nešto primljeno<< sReceivedChar; } }

To je zapravo cijeli primjer.

  • Analizirajte aktivnost serijskog porta

    Monitor serijskog porta može da se poveže na COM port, čak i ako je već otvoren od strane neke aplikacije, i odmah počne da ga nadgleda. Svi podaci koji prolaze kroz nadgledani COM port biće prikazani u našem programu za praćenje. Pošto se sve snima u realnom vremenu, moći ćete odmah uočiti probleme. Za poređenje podataka postoji funkcija sinkroniziranog odabira istih IRP-ova u različitim pogledima.

    Osim toga, možete preusmjeriti sve podatke praćenja na određenu datoteku ili kopirati sve snimljene podatke u međuspremnik. Monitor serijskog porta vam daje mogućnost presretanja i snimanja svih ulazno/izlaznih kontrolnih kodova serijskog porta (IOCTL), nadgledanje svih njihovih podataka i parametara. Možete sačuvati bilo koju sesiju praćenja i učitati je sljedeći put ako je potrebno.

  • Nadgledajte više portova unutar iste sesije

    Monitor serijskih portova ima jedinstvenu funkcionalnost za praćenje više COM portova istovremeno. Sada možete prikupljati podatke o tome kako aplikacije komuniciraju s dva ili više portova i paralelno s više uređaja unutar iste sesije. Primljeni i poslani podaci praćenja biće prikazani (snimani) u posebnom dnevniku redosledom kojim su primljeni, što uveliko pojednostavljuje analizu.

  • Različite opcije za pregled primljenih podataka

    Možete pregledati podatke praćenja u 4 načina odjednom: tabela, red, dump ili terminal, od kojih svaki nudi drugačiji način predstavljanja snimljenih serijskih podataka. Monitor serijskog porta vam omogućava da odaberete filtere za praćenje, čime vam štedi vrijeme i omogućava vam da nadgledate samo događaje od interesa. U postavkama možete odabrati podatke za prikaz: binarni, ASCII, konfigurirati port. Sve postavke prikaza mogu se primijeniti direktno u trenutnom procesu nadzora.

  • Emulirajte prijenos podataka na serijski uređaj

    Možete slati podatke u različitim formatima (string, binarni, oktalni, decimalni, heksadecimalni, mješoviti) na nadgledani serijski port kao da ih je direktno poslala kontrolirana aplikacija koristeći funkciju terminalskog načina rada Serial Port Monitor. Na taj način možete pratiti reakciju kontroliranog serijskog uređaja na neke posebne naredbe i podatke.

  • Potpuna podrška za Modbus protokol podataka (RTU i ASCII)

    Uz pomoć novih filtera Serial Port Monitor moći ćete dešifrirati i analizirati Modbus podatke. Program će pomoći ne samo u uspostavljanju veze između RS485/422/232 uređaja, već će i provesti efikasnu analizu prolaznih podataka.

  • Ponovite i uporedite sesije praćenja

    Monitor serijskog porta pruža jedinstvenu priliku za ponavljanje sesije od aplikacije do porta za najbolju analizu tekućih procesa. Moći ćete da posmatrate reakciju serijskog porta na prolazak istih podataka, čime se povećava efikasnost praćenja. Također imate opciju da uporedite više sesija praćenja i automatski pratite razliku između njih.

O tome kako lijepo predstaviti podatke koje Arduin šalje na Serial. Po mom mišljenju, momci su ponudili vrlo lijepo rješenje, koje s jedne strane izgleda prilično jednostavno, a s druge strane vam omogućava da dobijete odličan rezultat uz minimalan napor.

U komentarima na članak izrečeno je žaljenje što takvo rješenje neće funkcionirati pod Firefoxom, te je izražena ideja da "još uvijek možete napisati jednostavan web server sa html izlazom na osnovu ove stvari." Ova ideja me je „navukla“, brza pretraga na google-u nije dala gotovo rješenje, te sam odlučio sam implementirati ideju. A evo šta je iz toga proizašlo.

Upozorenje! Predloženo rješenje nikako ne treba smatrati potpunim. Za razliku od Amperkinog serijskog projektora, ovo je koncept, demonstracija mogućeg pristupa, radni prototip i ništa više.

Prije nekog vremena radio sam projekt u kojem sam koristio ugrađene akcelerometre u Android pametnom telefonu za kontrolu servo uređaja povezanih na Arduino. Zatim sam u ove svrhe koristio Scripting Layer za Android (SL4A) i RemoteSensors projekte. Ispostavilo se da standardna biblioteka python-a uključuje paket BaseHTTPServer, s kojim je podizanje web servisa u pythonu zadatak u nekoliko redova koda.

Nije bilo senzora za Arduino pri ruci, pa sam koristio interni termometar ugrađen u Arduino Uno kao izvor prikazanih informacija. Koliko sam shvatio, nije baš precizan i uopće nije namijenjen za mjerenje temperature okoline, ali će poslužiti za izradu prototipa.

Nakon kratkog guglanja, evo skice za arduino:

// izvor: https://code.google.com/p/tinkerit/wiki/SecretThermometer long readTemp() (dugi rezultat; // Očitavanje temperaturnog senzora prema 1.1V referentnom ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3); kašnjenje(2); // Pričekajte da Vref podmiri ADCSRA |= _BV(ADSC); // Pretvori while (bit_is_set(ADCSRA,ADSC)); rezultat = ADCL; rezultat |= ADCH<<8; result = (result - 125) * 1075; return result; } void setup() { Serial.begin(115200); } int count = 0; void loop() { String s = String(count++, DEC) + ": " + String(readTemp(), DEC); Serial.println(s) delay(1000); }
Ova skica otvara COM port, postavlja ga na 115200 baudova, a zatim svake sekunde upisuje trenutnu vrijednost ugrađenog termometra. (Ne pitajte me u kojim jedinicama je data temperatura - za opisani zadatak to nije bitno). Kako se vrijednost ne mijenja vrlo aktivno, radi bolje vidljivosti promjena podataka, prije temperature se prikazuje broj reda.

Da biste provjerili da li će web server izdati samo cijele linije, a ne njihove dijelove, kako čita sa COM porta, red
Serial.println(s)
je zamijenjen sa
for(int i=0; i< s.length(); i++){ Serial.print(s.charAt(i)); delay(200); } Serial.println("");
one. formirani niz se ne izlazi na serijski port u cijelosti, već karakter po karakter, sa pauzama od 200 ms.

Za početak je napisan vrlo jednostavan prototip web servera (ispod je rastavljen na dijelove):
# -*- kodiranje: utf-8 -*- #-- zasnovano na: https://raw.githubusercontent.com/Jonty/RemoteSensors/master/remoteSensors.py SERIAL_PORT_NAME = "COM6" SERIAL_PORT_SPEED = 115200 WEB_SERVER_0 PORT = vrijeme uvoza , BaseHTTPServer, urlparse import serial ser = None def main(): globalni ser httpd = BaseHTTPServer.HTTPServer(("", WEB_SERVER_PORT), Handler) #-- zaobilazno rješenje za dobivanje IP adrese na kojoj se servira import socket s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM) s.connect(("google.co.uk", 80)) sData = s.getsockname() print "Posluživanje na "%s:%s"" % (sData, WEB_SERVER_PORT) ser = serial.Serial(SERIAL_PORT_NAME, SERIAL_PORT_SPEED, timeout=0) httpd.serve_forever() class Handler(BaseHTTPServer.BaseHTTPRequestHandler): # Onemogući evidentiranje DNS pregleda def address_string(self): return str(self.clientGETsel) deff do_ self.send_response(200) self.send_header("Content-type", "application/x-javascript; charset=utf-8") self.end_headers() try: while True: new_serial_line = get_full_line_from_serial() ako new_serial_line nije Ništa: self.wfile.write(new_serial_line) self.wfile.write("\n") self.wfile.flush() osim socket.error, e: print "Klijent je prekinut.\n" captured = "" def get_full_line_from_serial(): """ vraća punu liniju iz serijskog ili Ništa Koristi globalne varijable "ser" i "captured" """ globalno uhvaćeni dio = ser.readline() ako dio: snimljen += dijelovi = captured.split("\n", 1); if len(dijelovi) == 2: snimljeno = dijelovi vraćaju dijelove vratiti Ništa ako __name__ == "__main__": main()
Hajde da razložimo scenario deo po deo.

Budući da je ovo prototip, svi glavni parametri rada (naziv COM porta, njegova brzina, kao i broj TCP porta na kojem će web server raditi) su naznačeni direktno u izvornom tekstu:
SERIAL_PORT_NAME="COM6" SERIAL_PORT_SPEED=115200 WEB_SERVER_PORT=8000
Naravno, možete urediti čitanje ovih parametara iz komandne linije. Na primjer, uz pomoć argparse modula to se radi vrlo brzo, jednostavno i fleksibilno.

U tom slučaju, korisnici Windows-a moraju u upravitelju uređaja saznati naziv COM porta na koji je Arduin povezan. Za mene je to bio "COM6". Korisnici drugih operativnih sistema moraju koristiti alate svog OS-a. Uopšte nemam iskustva sa MacOS-om, a nisam radio ni sa COM portovima na Linuxu, ali tamo će najverovatnije biti nešto poput "/dev/ttySn".

Zatim slijedi definicija globalne varijable na koju će biti vezana instanca klase Serial, koja je u pythonu odgovorna za rad sa COM portom:
ser = Ništa
U redu
httpd = BaseHTTPServer.HTTPServer(("", WEB_SERVER_PORT), rukovalac)
kreira se web server koji će slušati zahtjeve na navedenom portu WEB_SERVER_PORT. Ovim zahtjevima će upravljati instanca klase Handler, opisana u nastavku.

Sljedeći redovi su mali "hak" za prikaz IP adrese na kojoj je pokrenuti web server zapravo pokrenut:
#-- rješenje za dobivanje IP adrese na kojoj se servira import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("google.co.uk", 80)) sData = s.getsockname() print "Posluživanje na "%s:%s"" % (sPodaci, WEB_SERVER_PORT)
Koliko sam shvatio, ne postoji drugi način da saznate ovu IP adresu. I bez ovog znanja, kako ćemo pristupiti našem serveru iz pretraživača?

Stoga morate otvoriti utičnicu i povezati se na Google stranicu kako biste iz atributa ove utičnice izdvojili informacije o vlastitoj IP adresi.

Malo niže, otvara se COM port i zapravo se pokreće web server:
ser = serial.Serial(SERIAL_PORT_NAME, SERIAL_PORT_SPEED, timeout=0) httpd.serve_forever()
Nakon toga slijedi opis klase koja je odgovorna za obradu zahtjeva primljenih od strane pokrenutog web servera:
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
Ovo je nasljednik klase ugrađene u modul BaseHTTPServer, u kojoj je dovoljno nadjačati samo metodu do_GET

Pošto je ovo još uvijek prototip, server će biti “zadovoljan” svakim zahtjevom – bez obzira koji URL se od njega traži, klijentu će dati sve podatke pročitane sa COM porta. Stoga, u Handler.do_GET, odmah odgovara kodom uspjeha i potrebnim zaglavljima:
self.send_response(200) self.send_header("Content-type", "application/x-javascript; charset=utf-8") self.end_headers()
nakon čega se pokreće beskonačna petlja u kojoj se pokušava pročitati cijeli red iz COM porta i, ako je ovaj pokušaj bio uspješan, prenijeti ga na web klijent:
dok True: new_serial_line = get_full_line_from_serial() ako new_serial_line nije Ništa: self.wfile.write(new_serial_line) self.wfile.write("\n") self.wfile.flush()
U projektu koji je uzet kao osnova, ova beskonačna petlja je "umotana" u pokušaj ... osim bloka, uz pomoć kojeg je trebalo pažljivo da obradi prekid veze. Možda u Androidu (osnovni projekat je razvijen za njega), ovo radi dobro, ali meni nije išlo pod Windowsom XP - kada je veza prekinuta, dogodio se neki drugi izuzetak, koji nikada nisam naučio kako da presretnem. Ali, srećom, to nije spriječilo web server da normalno radi i prihvati sljedeće zahtjeve.

Funkcija dobivanja cijelog niza iz COM porta radi na istom principu kao i kreatori serijskog projektora:

  • postoji neki globalni bafer koji pohranjuje sve što se pročita sa COM porta
  • svaki put kada se funkcija pozove, ona pokušava nešto pročitati sa COM porta
  • ako uspije, onda
    • dodaje ono što je upravo pročitano u specificirani globalni bafer
    • pokušava podijeliti globalni bafer na najviše dva dijela znakom na kraju reda
    • ako uspije, onda vraća prvi dio pozivnoj proceduri i koristi drugi dio kao novu vrijednost globalnog bafera
  • ako nema novih podataka u COM portu ili znak na kraju reda nije pronađen, funkcija vraća None:
captured = "" def get_full_line_from_serial(): """ vraća punu liniju iz serijskog ili Ništa Koristi globalne varijable "ser" i "captured" """ globalno uhvaćeni dio = ser.readline() ako dio: snimljen += dijelovi = captured.split("\n", 1); ako len(dijelovi) == 2: snimljeno = dijelovi vraćaju dijelove vraćaju Ništa
Kao rezultat toga, ispalo je ovako:

Vidi se da se u pretraživaču pojavljuju linije koje se čitaju sa COM porta. Ne razumijem ništa o web frontendu: JavaScript, Ajax, CSS i DOM su za mene mračna šuma. Ali čini mi se da bi za programere koji kreiraju web interfejse ovo trebalo biti sasvim dovoljno da ovaj izlaz pretvore u istu prelepu sliku koju proizvodi Amperkin serijski projektor. Po mom mišljenju, zadatak je kreirati javascript skriptu koja pristupa web serveru, čita stream sa njega i šalje zadnji pročitani red na pravo mjesto na web stranici.

Za svaki slučaj odlučio sam da igram na sigurno i pokušao sam napraviti prvu aproksimaciju. Ne baš duboka Google pretraga je sugerirala da su se, u stvari, u takve svrhe, barem nekada koristili WebSockets ili Server-Sent Events. Našao sam ono što mi se činilo dobrom upotrebom serverskih događaja i odlučio sam da koristim ovu tehnologiju.

Bilješka! Čini se da ovo nije najbolje rješenje, jer ova tehnologija nije radila ni u Internet Exploreru 8, niti u pretraživaču ugrađenom u Android 2.3.5. Ali je radio barem u Firefoxu 39.0, tako da nisam dalje "kopao".

Sa stanovišta python skripte, promjene pod Server-Sent Events su potpuno male:

  • potrebno je zamijeniti tip podataka koji se daje klijentu:
    linija
    self.send_header("Content-type", "application/x-javascript; charset=utf-8")
    zamijenjen sa
    self.send_header("Content-type", "text/event-stream")
  • i također prije reda pročitanog sa COM porta, umetnite prefiks "data:" i dodajte još jedan znak za novi red:
    linije
    self.wfile.write(new_serial_line) self.wfile.write("\n")
    zamijenjen sa
    self.wfile.write("data: " + new_serial_line) self.wfile.write("\n\n")

Sve ostalo bi vjerovatno moglo ostati nepromijenjeno, ali...

Prvo sam napravio datoteku index.html sa sljedećim sadržajem:

header




Najzanimljivija u njoj je linija
koji formira mjesto za izlaz sljedećeg reda iz COM porta i javascript skriptu

koji zapravo čita tok sa web servera i šalje pročitane informacije na određenu lokaciju.

Namjeravao sam otvoriti ovu datoteku u pretraživaču, na primjer, s diska ili sa nekog drugog web servera, ali to nije išlo: prilikom otvaranja stranice s diska, javascript skripta je jednom pristupila pokrenutom Python web serveru i odmah prekinula vezu. Nisam razumio zašto se to događa, pa sam sugerirao da bi to mogla biti neka vrsta zaštite pretraživača od raznih napada. Vjerovatno mu se ne sviđa što se sama stranica otvara iz jednog izvora, a skripta čita podatke iz drugog izvora.

Stoga je odlučeno da se Python web server promijeni tako da služi i ovoj html stranici. Tada bi se ispostavilo da se i stranica i stream čitaju iz istog izvora. Ne znam da li je moja pretpostavka o sigurnosti ispala tačna, ili nešto drugo, ali sa ovom implementacijom sve je funkcioniralo kako treba.

Naravno, trebate samo promijeniti klasu rukovatelja zahtjeva Handler:
class Handler(BaseHTTPServer.BaseHTTPRequestHandler): # Onemogući evidentiranje DNS pretraživanja def address_string(self): return str(self.client_address) def do_GET(self): if self.path == "/" ili self.path == "/index .html": self.process_index() elif self.path == "/get_serial": self.process_get_serial() else: self.process_unknown() def process_index(self): self.send_response(200) self.send_header("Sadržaj -type", "text/html; charset=utf-8") self.end_headers() self.wfile.write(open("index.html").read()) self.wfile.write("\n\ n") self.wfile.flush() def process_get_serial(self): self.send_response(200) self.send_header("Content-type", "text/event-stream") self.end_headers() try: while True: new_serial_line = get_full_line_from_serial() ako new_serial_line nije Ništa: self.wfile.write("data: " + new_serial_line) self.wfile.write("\n\n") self.wfile.flush() osim socket.error, e : print "Klijent je prekinut.\n" def process_unknown(self): self.send_response(404)
Ova opcija pretpostavlja da će web server odgovoriti samo na dva zahtjeva: "/index.html" (davanje html koda stranice) i "/get_serial" (davanje beskonačnog niza nizova čitanih sa COM porta). Na sve ostale zahtjeve će biti odgovoreno sa 404 kodom.

Budući da index.html opslužuje Python web server, može se malo izmijeniti specificiranjem relativne umjesto apsolutne adrese string toka iz COM porta:
string
var source = new EventSource("http://192.168.1.207:8000/")
zamijenjen sa
var source = new EventSource("/get_serial")
Kao rezultat toga, ispalo je ovako:

Tu sam odlučio da prekinem. Čini mi se da bi lijepo dizajniranje stranice već trebalo biti prilično jednostavno. Ali nisam vešt u HTML-u ili CSS-u, pa neka to radi neko drugi. Vidio sam svoj zadatak u tome da pokažem da pravljenje web servisa koji šalje podatke sa COM porta, čini se, nije nimalo teško.

Ponavljam još jednom: predstavljeni kod nije kompletno rješenje koje se može „pustiti u proizvodnju“. Ovo je samo prototip, koji pokazuje fundamentalni pristup rješavanju problema.

Na čemu se još može raditi:

  • prvo, čitanje podataka sa COM porta u python skripti se obavlja veoma "nespretno" - u stvari, postoji konstantno ispitivanje "ima li nešto sveže?". Ovakav pristup, naravno, opterećuje procesor i jedno jezgro na mom računaru je 100% zauzeto.
    Blokiranje čitanja s timeoutom može se koristiti kao rješenje. Da biste to učinili, dovoljno je navesti vrijednost koja nije nula (u sekundama) kao timeout prilikom otvaranja COM porta, na primjer:
    ser = serial.Serial(SERIAL_PORT_NAME, SERIAL_PORT_SPEED, timeout=0.03)
    Osim toga, u opisu pySerial modula postoje tri primjera kreiranja mosta: "TCP/IP - serijski most", "Single-port TCP/IP - serial bridge (RFC 2217)" i "Multi-port TCP /IP - serijski most (RFC 2217)" - možete vidjeti kako profesionalci rješavaju takve probleme.
  • drugo, samo jedan klijent može primiti podatke. Dok se stranica ne zatvori na prvom klijentu, ne možete se povezati na taj server i dobiti vrijednosti na drugom računaru. S jedne strane, ovo je vjerovatno tačno: postoji samo jedan COM port, a postoji nekoliko potrošača - koji od njih treba dati red za čitanje? Ako mislite da bi odgovor na ovo pitanje trebao biti "svi", evo mojih misli o tome. Čini mi se da se problem ne može riješiti samo korištenjem "poštenog" multi-threaded web servera (na primjer, neki Tornado ili Flask), koji može istovremeno opsluživati ​​zahtjeve od više web klijenata. Budući da ne možete otvoriti COM port iz svake niti i čitati iz nje - u ovom slučaju podaci iz COM porta će ići samo u jednu nit/proces. Stoga je po mom mišljenju potrebno serverski dio podijeliti na dva dijela:
    • zmq server koji radi sa COM portom, čita linije sa njega i šalje ih preko PUB socketa svim zainteresovanim potrošačima
    • python web server umjesto povezivanja na COM port povezuje se sa zmq serverom i prima podatke sa njega
    Ako niste upoznati sa ZMQ (ZeroMQ) bibliotekom, onda umjesto toga možete koristiti obične TCP/IP ili UDP utičnice, ali bih vam toplo preporučio da se upoznate sa ZMQ, jer ova biblioteka olakšava rješavanje takvih problema. Čini mi se da će uz pomoć ZMQ-a rješenje stati u maksimalno 20 redova. (Ne mogu odoljeti da ne napišem: čak i ako ne planirate rješavati opisani zadatak, ali je vaš posao vezan za višenitno/višeprocesno programiranje s razmjenom podataka između niti/procesa, pogledajte izbliza ovu biblioteku - možda je to ono o čemu ste tako dugo sanjali)
  • tok podataka je i dalje jednosmjeran - od COM porta do web pretraživača. Još ne možete slati podatke iz pretraživača na Arduino. Čini mi se da i ovaj zadatak nije jako težak i, za razliku od prethodnog, može se samo riješiti
    • koristeći višenitni server
    • doradu metode Handler.do_GET tako da prihvata GET zahtjeve s parametrima i šalje vrijednosti određenih od njih na COM port
    Po mom mišljenju, ako želite napisati punopravni analog web-baziranog monitora serijskog porta ugrađenog u Arduino IDE, to nije tako teško. Lično, za sebe, vidim poteškoću samo u stvaranju normalnog frontenda.
  • još nije moguće podesiti naziv COM porta i parametre njegovog rada preko pretraživača. S jedne strane, ovo izgleda logično: kako korisnik s druge strane naše planete može znati na koji COM port i kojom brzinom je povezan arduino? Ali Python web server koji radi na istom računaru sigurno zna. Ali ako je i dalje poželjno dati korisniku priliku da promijeni ime COM porta ili parametre njegovog rada, onda se to opet može lako riješiti preciziranjem metode Handler.do_GET
  • python je neophodan za pokretanje servera. To općenito nije teško, ali ako se iz nekog razloga to ne može učiniti ili ne želite, onda pyInstaller može priskočiti u pomoć. Sa njim se Python skripta može kompajlirati u jednu izvršnu datoteku (u slučaju Windowsa - u .exe), koju je lako kopirati na računar na koji je povezan arduino.
    Možda bi najbolje rješenje bilo korištenje Go jezika u ovom slučaju. Koliko ja znam, to bolje rješava problem kreiranja fajla za "distribuciju".
U zaključku: može se postaviti pitanje: "nije li lakše riješiti ovaj problem kroz neki gotov oblak?". Zašto ne objaviti podatke čitljive sa COM porta u oblaku, a na klijentima jednostavno pristupiti odgovarajućoj usluzi u oblaku? Vjerovatno i takvo rješenje ima pravo na postojanje, ali prije primjene takvog rješenja potrebno je odgovoriti na sljedeća pitanja:
  • Postoje li gotovi web servisi koji mi omogućavaju da objavljujem podatke brzinom/frekvencijom koja mi je potrebna? Ima li među njima besplatnih ili ste spremni platiti odgovarajući novac?
  • jeste li spremni na to da u slučaju pada oblaka ili veze s njim ostanete bez podataka
  • Ne smeta li vam što će za prijenos podataka iz jedne prostorije u drugu preći dva puta okean ili pola kontinenta?


Učitavanje...
Top