Programare

Pai incerc sa migrez de la Firebird / Interbase ca ala nu vrea sa se cross-compileze. Pana acum SUXX! M-am chinuit juma' de zi numai sa fac mysql-ul sa porneasca in 180MB RAM liber si cu un cont root care nu se cheama "root".
 
Marius '95 , spaima logicii in functionarea oricarui sistem IT :biggrin:. Initial eram WTF cand ii auzeam necazurile, acum doar ma amuz.
Client de MySQL folosesc cel text, mysql.exe. Desi nu sunt adeptul cli-ului in general, in cazul acesta il prefer GUI-urilor.
 
Eu folosesc cli-ul pentru chestii de administrare în principal (un source backup.sql, show processlist, kill whatever), dar n-am vreo șansă să scriu asta în linie de comandă...

Code:
update col_match cm set taxonID = (select taxonID from col2019.taxon tx  where concat(cm.scientificName, ' ', replace(replace(authorship, ',', concat(' ', author_in, ',')), '.', '. ')) = tx.scientificName), match_type='species+author dots and author in'
where 1 = (select count(1) from col2019.taxon tx  where concat(cm.scientificName, ' ', replace(replace(authorship, ',', concat(' ', author_in, ',')), '.', '. ')) = tx.scientificName)
and cm.taxonID is  null and authorship is not null and author_in is not null;
 
Păi numa' tu ai probleme de-astea...
Oh really? Serveste-o p-asta:
In toate programele mele PHP din ultimii 10 ani am folosit functii wrapper pentru comunicarea cu baza de date. Ma asteptam sa trebuiasca sa schimb baza de date si nici in ruptul capului n-as mai fi modificat toate programele. As fi modificat doar functiile astea. Ei, pana acum n-a fost nevoie. A mers Firebird-ul fara nici o problema. Functiile arata asa:
- M95SQL() => face conectarea la baza de date. E mai mult interna, ca e apelata din celelalte functii daca nu-i nici o conexiune deschisa.
- M95SQLTrans(), M95SQLCommit(), M95SQLRevert() => deschide / salveaza / anuleaza o tranzactie
- M95SQLPrep(string $query) => face un prepared statement si returneaza variabila (resource)
- M95SQLExec(resource $prep_stmt, array $data) => executa statement-ul cu datele din array (oricate ar fi) si returneaza array cu toate randurile (select) sau int cu nr. de randuri afectate (insert/update)

Acum, a se construi functia generica M95SQLExec() pentru PHP7 si mysql/mariadb=> EPIC FAIL
De ce? Pentru ca, spre deosebire de Firebird,
- Nu merge direct execute, trebuie intai bind_param
- bind_param nu merge direct cu lista de variabile, vrea si TIPUL LOR!!! Deci pune-te si inspecteaza fiecare varibila din array sa vezi ce tip e!
- Big fucking problem cu NULL, ca n-are tip definit! Cauta... citeste... testeaza...
- Mai intreaba unu' speriat ce se intampla daca trebuie introdus un SQL bigint, ca int din php e mai mic! OH F**KING SHIT!!! AM SI EU BIGINT!!! Stai iar si cauta... citeste... testeaza...
- Nu mai merge sa faci direct call_user_func_array("mysqli_stmt_bind_param", $arr_data), ca trebuie pass by reference. Deci hai ca asta e usor dupa ce ai inspectat tipul de variabile!
- execute nu mai returneaza direct rezultatul sa-l iau cu fetch. Trebuie bind_result.
- Dar stai! bind_result vrea lista de coloane. De unde naiba sa stiu lista de coloane intr-o functie generica?!?!

Bah, astia chiar gandesc cu curu'!?
Hai zi ca numai eu fac wrapper pentru SQL sau numai eu fac SELECT * cu prepared statement?
 
Last edited:
Păi numai tu faci wrappere manual pentru SQL. În rest lumea folosește biblioteci, și fac alea toată traducerea către whatever bază de date vrei tu, fără să mai faci mare lucru. Dacă tot schimbi tot, măcar folosește PDO dacă nu ceva mai serios (caz în care nu-ți mai pasă de tipuri and stuff). Toți ăia care suferă de Not Invented Here cât suferi tu cam au aceeași soartă ca tine, înjură la fiecare modificare de versiune de whatever. Adică trebuie să îți asumi că lumea se mișcă pe lângă tine, și dacă nu folosești ce folosesc și ei vei avea mai mult de lucru.

Zilele astea a trebuit să migrez o aplicație scrisă în 2007 de la Oracle la MySQL. A durat câteva minute să schimb sursa de date, să pun driver-ul de mysql și să schimb 2 query-uri manuale care foloseau sintaxa Oracle de outer join-uri (+). Pentru că tot SQL-ul e wrapat într-o bibliotecă, nu se atinge nimeni direct de el.
 
Nu pot PDO ca nu stiu 'OO'. Si cu bibliotecile la fel. Toate's cu 'OO'.
De vreo 4 ori am incercat sa invat. N-am reusit.

PS: Incep sa am senzatia ca programatorii asta de azi isi cam dau de lucru unii altora. Acu' 30 de ani scria unu un program in cobol, nici naiba nu se atingea de el minim 10 ani. Acum, la fiecare 6 luni, versiune noua de nu-stiu-ce componenta/bilblioteca/kernel/whatever, nu mai e compatibila cu nu-stiu ce alta chestie => trebuie updatat un lant intreg de dependinte care la randul lor nu mai sunt compatibile cu alte programe si ajungi in final la a schimba tot sistemul. Macar la cobol se facea asta doar la 10-20 ani...
 
Last edited:
Păi minimizează ce trebuie să știi despre OO, că nu-i pasă nimănui de moșteniri, suprascrieri de funcții, clase abstracte and so on doar ca să folosești un PDO:
- clasă = o structură care organizează niște date (variabile interne) și definește niște funcții pe care le poți apela; ex: o clasă ar putea fi structurată ca un rând din baza de date, fiecare coloană câte o variabilă din interiourul clasei
- obiect = instanță = datele efective în memorie conform structurii definite de clasă, ex: rândul efectiv când îl citești din baza de date

Ca să creezi un obiect, pornești de la clasă și zici $obiect = new Clasă(); asta alocă memoria pentru variabilele interne. Ca să se simplifice treaba, clasele pot avea constructori (pe care îi apelezi ca să inițializezi câte ceva direct din call-ul new)
Ca să accesezi o funcție din interiorul obiectului, folosești ->, deci $obiect->funcție(); poți avea variabile interne care-s disponibile direct în acest mod (publice).

Funcțiile din clasă mai au o variabilă specială $this, care trimite către instanța obiectului, adică poți să accesezi variabilele din interior cu $this->var1
 
Mi-a sosit un M5StickC, dupa 5 saptamani de asteptare. Chiar nu credeam ca mai vine.

Asa, dupa cum ma cunoasteti voi :fluier:, ce IDE/suita/compilator/limbaj/etc. pentru ESP32 mi s-ar potrivi? :biggrin:
Thx.
 
OK, am pus Arduino IDE intr-un Win7 virtual, am incarcat cateva demo-uri si am si incercat ceva f. basic cu biblioteci (gen, conectat la wifi, subscribe la un topic MQTT si afisat pe serial mesajele).
Comparativ cu LPC21xx si IDE-ul de la Keil, asta e sinistru. Fundal alb obositor, fontul nu se poate schimba, culorile nu se pot schimba, nu stie aliniere cu tab, si e foarte foarte foarte lent. Programul ala pe LPC se compila in <1s. Cel mai basic program ESP32 se compileaza in min. 1 minut.
Documentatia e practic absenta pentru orice. Trebuie sa deschid demo-urile bibliotecilor si sa copiez bucati din exemple. Si bineinteles tipurile de variabile nu-s documentate. Unele functii primesc char*, altele String (dracu' stie ce-o fi ala). Nicaieri nici o metoda de conversie intre astea doua. Nicaieri nu scrie cat de lungi pot fi string-urile alea, cum sunt terminate. Nimic. Pauza.
Daca vreau sa vad cum functioneaza intern o biblioteca, constat sa se bazeaza pe alte 10 de biblioteci, care la randul lor.... si uite asa imi vine instantaneu sa-mi bag piciorul.
Si ca sa fie pus capacul complet, nu am gasit nici o metoda de a scrie un program fara sa import nimic. Nici macar nu am gasit acel fisier .h cu adresele registrilor cum era la LPC.

TLDR: I hate it.

PS: Si acel esp-idf e un sistem de operare intreg: FreeRTOS la care ar trebui sa mai adaug programul meu. Acolo chiar n-am nici o sansa sa fac ceva non-bloatware.
PS2: Am senzatia ca si Arduino IDE include tot FreeRTOS-ul, doar ca n-am sapat eu destul in bibliotecile alea obligatorii. Deci sux.
 
Last edited:
String e inamicul tău numărul 1, un obiect :biggrin:. Are un constructor care acceptă cam orice, adică dacă ai un char* a, zici String(a) și ai făcut un String. La fel String(10) etc. Șirurile de caractere se termină normal, cu \0, dar nu-mi aduc aminte să fi avut nevoie să scriu asta vreodată.

Da, compilarea în IDE-ul arduino e lentă. Nu te obligă nimeni să folosești de fapt IDE-ul, poți să editezi în ce vrei tu și să compilezi din linie de comandă.

Comparația cu Keil e un pic forțată. Licența pentru Keil MDK pe 1 an e între $1800 și $4500 per user. Da, există versiunea aia Lite, dar e limitată destul de rău. Față de Arduino IDE care e gratuit... asta e, nu poți face multe optimizări când n-ai bani.

Documentația bibliotecilor e foarte variată, de la chestii bine făcute gen ArduinoJSON, la hălci de cod într-o pagină web cu maxim un exemplu. Dar funcționează :smile:.
 
TL;DR: bag piciorul în el de strung, cine a inventat imbecilitatea asta de unealtă complicată, atâtea reglaje de învățat, atâtea subansamble făcute de alții, și mai ales un mod de lucru complet rigid și pe care EU să îl adopt. Ia ziceți-mi, ce e în neregulă cu un băț mai zdravăn de care e legat un bolovan de bazalt? O unealtă simplă, clară, nimic de comentat sau greu de înțeles, pot să aleg din ce lemn să fie bățul și cât de greu sau ce culoare să fie bolovanul, vezi dacă poți la strung să-ți alegi măcar culoarea vopselii lui. Vremurile moderne sux.
 
Sa-mi zica si mie cineva ce tip e ala portMUX_TYPE si ce face functia portENTER_CRITICAL_ISR
N-am gasit documentat nicaieri.
Multumesc.
 
Iar ai ajuns la niște chestii de prins urechile tipice Marius '95, pe care 99.999% din ceilalți nu le folosesc :biggrin:.

Critical section e o metodă de programare (întâlnită în embedded și kernel stuff mai mult) care face secțiunea dintre enter_critical și exit_critical atomică, astfel încât să asigure că accesul la resurse (memorie, porturi etc) nu e modificat până nu se termină secțiunea (de întreruperi sau de alte thread-uri, care rulează pe alt core, de exemplu). Atomicitatea se asigură printr-un mutex - în cazul ăsta de tip portMUX_TYPE, care e un spinlock. Ideea e că thread-ul care ajunge primul la zona critică ia lock-ul, iar celelalte așteaptă până iese. Please google it dacă vrei mai mult, sunt cursuri de facultate care acoperă mutecși and stuff pe parcursul a câtorva ore cel puțin - dar gândește-te la ceva de genul pui o variabilă pe "1" când ești în zona critică și celelalte operații bagă un while variabilă ==1); înainte să intre și ele în zona critică; doar că e ceva implementat hardware care ajută cu sincronizarea.

Ideea e că poate ai o întrerupere care modifică o zonă de memorie, dar în thread-ul principal tu poate faci altceva cu zona aia de memorie (ex: faci o medie pe un array care e modificat de întrerupere); ca să nu ai rezultate incorecte, bagi ambele într-o secțiune critică folosind același mutex. Vezi că mutex-ul trebuie să fie vizibil de toată lumea și nu trebuie suprascris, adică îl faci global și static.

Vezi și că portENTER_CRITICAL e o funcție care nu ar trebui folosită de o aplicație "normală" - există taskENTER_CRITICAL, care face același lucru dar e posibil să ai mai puține probleme cu ea :smile:.
 
Pai si unde e documentat portENTER_CRITICAL si taskENTER_CRITICAL, ca sa vad si eu diferenta?

ESP32. Fac bit-banging pe un GPIO. Fiecare bit are 355 us. M-am gandit sa fac un timer cu IRQ cu durata asta. Cand suna ceasul, functia IRQ seteaza urmatorul bit pe GPIO.
Ca sa nu stea o vesnicie in functia aia, urmatorul bit e pregatit in main loop.
DAAAR! ESP32 e dual-core. Cica trebuie un mutex din ala, desi nu prea inteleg cum ar putea sa se incurce la o singura variabila tip char(?!).
Siiii... din cauza ca Arduino IDE nu are implementate functiile de sleep, trebuie sa fac tot un fel de spinlock in main loop in timp ce astept ca functia IRQ sa "consume" bitul pregatit. Dar asteptarea trebuie sa verifice tot timpul bitul ala, adica sa puna lock pe mutex, ceea ce inseamna ca in momentul intreruperii cu timer, sunt sanse mari ca variabila sa fie "blocata" => rateaza momentul cand trebuie schimbat GPIO-ul.
Si, bineinteles, avand WIFI care banuiesc ca tot pe baza de intreruperi functioneaza, nu scrie nicaieri care intrerupere are prioritate: timer-ul sau wifi-ul.
Absolut horror.

Oare astia de la NXP cand scot un competitor pentru ESP32?
 
Prin freeRTOS, care e folosit "în spate".

Probabil codul tău n-o să aibă probleme de timing, pentru că în ESP32 CORE1 default folosit de codul custom, iar CORE0 e în principal de wifi/bluetooth. Cât timp nu pui întreruperi pe CORE0, ar trebui să nu te deranjeze.

Nu mi-e clar ce faci cu biții ăia, de trebuie să-i pregătești pe fiecare în parte; în mod normal bagi totul într-un array și îl dai funcției de trimitere și gata. Iar în 355us poți să rulezi o tonă de cod, nu știu dacă nu te complici prea mult.
 
Naiba stie pe ce core se executa, ca nici asta nu scrie nicaieri.

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 si 8 biti comanda.
Daca ar fi sa fac array, as avea antetul, care nu-i cu biti si nu-l pot pune in array, 4 bytes adresa, din care ultima jumate de bit trebuie inlocuita dupa nevoi, si 1 byte comanda.

Deci, da, e o tona de cod de executat ca sa aflu ce on/off urmeaza. Plus ca digitalWrite pe GPIO am inteles ca mananca vreo 10us sa se execute.
 
Back
Top