Programare

Nu faci shift, ții un contor de "bit" și îl calculezi on the fly din array. Că nu ai nevoie să faci shift, nu te ajută cu nimic.

char getbit(char* a, int pos){
return bitRead(a[pos/8], pos%8);
}

Ești sigur că nu e un protocol cât de cât standard și n-a implementat altcineva asta deja? :)
 
Ce naiba e ala bitRead()?? Ce .NET framework tre sa mai import si pentru ala? [/rant]

Testez cand ajung acasa. Thx.

Sunt convins ca n-a mai scris nimeni protocolul (open source adica). E telecomanda de la rulouri. :P
 
bitRead e un macro. Poți să îl scrii direct, dacă vrei neapărat
Code:
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
 
Merge!
Testat cu LED-ul onboard si timer de 0.5 secunde. Clipeste corespunzator codului, dar pe dos! Adica acolo unde e digitalWrite(LED,1), LED-ul se stinge, iar unde e digitalWrite(LED,0), LED-ul se aprinde. :insane:
 
Corect. LED aiurea. Pe GPIO merge cum trebuie.

Deci:
- Wifi merge, se conecteaza, etc.
- MQTT merge, se conecteaza, face subscribe, primeste mesajele, etc.
- Semnalul pe GPIO se trimite cum trebuie.
- Emitatorul radio 433MHz merge. Rulourile primesc comanda de test si se ridica.
:majoreta:

Acum, care ar fi cea mai simpla metoda sa trimit comanda printr-un mesaj MQTT?

1) Stochez toate combinatiile adresa+canalul+comanda in ESP32 si trimit ceva f. scurt prin MQTT, gen "r1u" (rulou 1 up), "r2d" (rulou 2 down), care selecteaza una din comenzi.
Avantaj: simplu de selectat, transmis. Codul MQTT poate fi orice; asta inseamna ca pot face subscribe la topicul altui device IOT si sa folosesc mesajele publicate de ala.
Dezavantaj: fiecare combinatie trebuie definita separat si sunt 12.

2) Stochez adresa si comanda in ESP32, dar separat. Adaug canalul (din MQTT) si comanda dupa adresa inainte de a o transmite. MQTT idem 1).
Avantaj: am toate combinatiile posibile disponibile. Idem codul MQTT.
Dezavantaj: mult cod de scris pentru reunitul tututor celor de mai sus.

3) Stochez doar parametrii de transmisie (intervale, cum arata 0, cum arata 1), fara codul efectiv. Trimit codul prin MQTT.
Avantaj: am absolut toate combinatiile posibile, chiar si viitoare, in cadrul aceluiasi protocol.
Dezavantaj: Codul MQTT este String sau char* si trebuie convertit. Nu mai pot folosi mesajele altui device IOT.

4) Nu stochez absolut nimic, nici macar parametrii de transmisie. Trimit absolut totul prin MQTT. Ma gandesc sa impachetez totul in JSON, ca am vazut ca exista biblioteci garla. O fi vreuna si documentata...
Avantaj: Este independent de protocol. Pot trimite orice cod pentru orice device fara sa mai modific vreodata sursa.
Dezavantaj: Mesajul MQTT va fi f.f. lung si programul f. f. mare.

PS: Constat ca nu prea stiu cum se foloseste MQTT. Cum ar trebui sa se interconecteze device-urile? Fiecare device cu topicul lui? Toate in acelasi topic, dar comenzi diferite? Daca am un senzor de temperatura, de exemplu, cine ia deciziile si face legatura intre senzor si roulouri / lumini / aer cond. / etc?
 
Last edited:
N-ai dat suficiente date, ce e canalul, ce e adresa etc. But anyway, cât timp nu ai mai multe device-uri de transmisie nu cred că are rost să ții implementarea în 2 locuri diferite. Din exterior ar trebui să trimiți o comandă (up/down) și cine s-o facă (rulou 1, rulou 2). Tot restul de implementare ar trebui să fie lângă hardware. Nu mi-e clar ce înseamnă că fiecare combinație trebuie definită separat - nu e o adresă și o comandă?

Vezi că MQTT nu e chiar făcut pentru mesaje lungi.

Să fii atent la deconectări pe wifi și mqtt, trebuie monitorizate că stau conectate, altfel poți să pierzi mesaje.
 
Am 3 ferestre cu rulouri electrice. Fiecare fereastra are o telecomanda cu o adresa unica si 1-2 motoare care actioneaza rulourile. Fiecare motor are un canal separat, bitii 28-31 din adresa, ca sa poata fi actionat independent, canalul 0 actionand simultan pe toate motoarele de la fereastra aia. Telecomanda are 3 comenzi, sus, jos si stop. Comanda stop e simpla, dar sus si jos sunt de fapt cate doua comenzi separate transmise consecutiv. Am senzatia ca prima comanda este pentru "sus", iar a doua este ceva de genul "continua pana la capat". Trebuie sa mai testez.
E complicat cu bitii. Pe GPIO, bitul "0" se transmite ca on-off-off, 355us fiecare, bitul "1" se transmite ca on-on-off.
E un antet de 6500us care nu-i nici 0, nici 1, si trebuie alta logica sa-l trimit, apoi 28 de biti adresa device-ului, 4 biti adresa din device (canalul) si 8 biti comanda.
Ma atrage varianta 4, ca mai am centrala termica cu termostat radio (alt protocol), iar device-ul are si un LED IR, ceea ce inseamna ca, teoretic, as putea controla si AC si TV-ul doar schimband GPIO-ul.
 
Știu că te atrage, că e cea mai complicată chestie posibilă, dar e ca și cum atunci când ar trebui să deschizi ruloul ar trebui să apeși pe butonul telecomenzii repede un cod :)). Implementarea ar trebui ascunsă dacă nu îți trebuie (și clar nu-ți trebuie, chiar dacă ai zice că da). Dacă o să vrei să deschizi ruloul din două locuri diferite (ex: mqtt dash de pe telefon) va trebui să ții șirul ăla dubios cu semnalul în ambele locuri. Și mult succes să mai înțelegi după 10 minute pentru ce era șirul ăla de on/off.
 
Vreau un log care sa fie afisat pe ecran.
Am definit char log[<linii>][32], dupa dimensiunile ecranului si un char logCursor care indica cea mai veche linie, aceea care urmeaza a fi suprascrisa. Am facut si functia care scrie continutul log-ului, in ordine, pe ecran.
Care ar fi cea mai simpla metoda sa scriu mesaje in log? Mentionez ca mesajele contin de obicei niste text urmat de valoarea unei variabile int. Planuiesc sa n-am linii mai lungi de 32 de caractere.
In incercarile mele m-am lovit de "warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]", unde n-am mai inteles nimic si am lasat-o balta.
 
String constant e ceva de genul "aaaa", care e constantă; ca funcția ta să accepte așa ceva fără să facă urât trebuie să îi pui tipul const char* în loc de char*. const char * sunt alocate în alte zone de memorie și sunt refolosite oriunde e nevoie de acel string, de-aia face urât la utilizare ca char* (caz în care ai putea modifica lucruri pe-acolo)

Vezi sprintf (posibil cu %s.32, ca să truncheze) sau strcpy.
 
Voi mai stiti statistica?

C in Arduino IDE:
Cum fac sa generez simplu niste numere aleatorii cu distributie:
- dinte de fierastrau = numere mai frecvente la unul din capetele intervalului si f. rare sau deloc la celalalt capat
sau:
- triunghiulara = numere frecvente la mijlocul intervalului si f. rare sau deloc la capete,

As vrea direct codul, nu biblioteca, daca se poate.
Multumesc.
 
Păi iei un random number generator și aplici o transformare pe el; pentru o distribuție dinte de fierăstrău e simplu, x = sqrt(random()); pentru triunghiular, pui doi dinți de fierăstrău condiționați de valoarea inițială (dacă r=random() e între 0 și 0.5 aplici sqrt(r), dacă e între 0.5 și 1 aplici 1-sqrt(r).

1595311125243.png


Implementarea random() și sqrt() fără biblioteci râmăn temă pentru acasă.
 
Nope. Nu merge.
sqrt(din-ceva-random) da ceva la fel de random si la fel de plat distribuit, dar pe un domeniu mai mic. In final, sqrt(rand(1,100)) == rand(1,10).
 
Mda, random din arduino face altceva decât ce sunt eu obișnuit (ca rand să dea un număr între 0 și 1). Poți emula cu r = random(0,10000)/10000.

Graficul de mai sus a fost obținut din script-ul de mai jos, care numără probabilitățile pe 100 de buckets de întregi. Nu reduce intervalul, pentru că expandarea la ce interval vrei tu se face după radical (radicalul unui nr. între 0 și 1 este tot între 0 și 1).

Code:
from random import random
from math import sqrt

prob1 = {}
prob2 = {}


for i in range(0,10000):
    r = random()
    # uniform
    j = int(r * 100)
    prob1[j] = (prob1.get(j) if prob1.get(j) else 0) + 1

    # crescator
    k = int(sqrt(r) * 100)
    # print(r, j, k)
    prob2[k] = (prob2.get(k) if prob2.get(k) else 0) + 1

for i in range(0,100):
    print(str(i) + '\t' + str(prob1.get(i)) + '\t' + str(prob2.get(i)))

Poți să-l încerci aici https://www.katacoda.com/courses/python/playground
 
Ma joc cu un LPC2148. Are USB.
Evident, exista o biblioteca pentru el, ceva gen USB stack. M-am uitat in ea si nu mi-a placut ce am vazut. 9 fisiere cu 53 KB de cod slab comentat.
Acum imi scriu propria implementare USB 2.0 pentru un port serial (USB CDC).

A mai facut cineva chestia asta? Am intrebari specifice. :jumpy:
 
Stack TCP/IP am mai scris (cu tot cu interfațare placă de rețea NE1000 pe ISA), da' la USB am abandonat (pe vremea aia abia apăruse USB 2, era un proiect pentru un sniffer de USB, că pentru 2.0 nu prea existau pe piață).

Ce să zic, mult succes!
 
Am un buffer gen char cmd[256], un cursor pentru scriere (coada bufferului) si unul pentru citire (capul bufferului). Buffer-ul contine operatii USB. Fiecare operatie are 2-3 comenzi, fiecare comanda are 2 bytes si main() adauga 1-4 operatii odata in functie de necesitati. Comenzile sunt ciitite de o intrerupere. Intrucat main() scrie la coada bufferului si intreruperea citeste din capat, cele doua nu interfereaza reciproc indiferent ce/cate operatii/comenzi sunt scrise.
Daaar:
Uneori survine o alta intrerupere (eroare, status change) pentru care trebuie sa trimit imediat o operatie (2-3 comenzi care determina ce eroare este sau ce s-a intamplat), "in fata" bufferului. Cum fac asta usor? Inca un buffer, prioritar?

Am incercat sa "dau inapoi" capatul bufferului si sa inserez operatia noua acolo, dar nu merge, ca fiecare operatie are 2-3 comenzi si daca tocmai se executa #1 si inserez altceva inainte de #2, cand ajung iar la #2, pica prost.

PS: Biblioteca nu trateaza erorile. De fapt, biblioteca nici nu foloseste intreruperile pana nu-i totul configurat.
 
Dacă-s pachete de comenzi care trebuie grupate în operații, atunci un buffer liniar de comenzi nu pare util, pentru că executorul nu știe când s-a terminat o operație - pare că-ți trebuie o coadă de operații, fiecare cu lista ei de comenzi (array de array de comenzi, dar mai degrabă un struct cu pointeri la liste de comenzi). Iar acolo ai putea pune și prioritate pe fiecare operație.
 
Last edited:
Array bidimensional adica? Am mai facut dar n-o sa mearga aici pentru ca in cadrul operatiei doar prima comanda e comanda propriu-zisa; dupa ea urmeaza date sau 1-2 comenzi de citire date, deci e ceva variabil si ca lungime si continut.

La restul m-ai pierdut. O sa iau manualul de C la puricat cand am timp.

Intre timp ma frustreaza uart-ul, ca intreruperile imi baga debug-ul lor in mijlocul debug-ului de la main().
 
Back
Top