Italian community of Lazarus and Free Pascal

Programmazione => Componenti Aggiuntivi => Topic aperto da: Diego1981 - Giugno 05, 2022, 04:47:59 pm

Titolo: Synapse e Domotica
Inserito da: Diego1981 - Giugno 05, 2022, 04:47:59 pm
Ciao A tutti
è da un bel po' che non entro nel forum ma vedo che è sempre molto attivo...
volevo avere il parere di qualcunche usa synapse.
visto che il mio vecchio impianto è saltato con un bel fulmine ho ammodernato le schede di domotica e ora è tutto over IP
ho probelmi con una scheda che utilizza le "stringhe" esadecimali ma il problema è che non riesco a ricevere tutti i byte che dovrei, ho utilizzato anche altri software e con quelli ricevo tutto correttamente
come libreria usa synapse e il codice che uso è molto semplice
PER INVIARE (E FIN QUI TUTTO OK)

procedure.........invo
var
  HexString,StrChr:String;
  Str,i:Integer;
begin
HexString:='5E0123C001000000000000000000000000000000000000000000000000000000000000000000000000000000FF';
    StrChr:='';
    Str:=0;
    i:=1;
    while i<=Length(HexString)do
      begin
        Str:=Hex2Dec(HexString+HexString[i+1]);
        StrChr:=StrChr+Chr(Str);
        i:=i+2;
      end;
    ArrSckt[ScktIndx].Sckt.SendString(StrChr); 
end;

QUESTA è LA "STRINGA CHE RICEVO"
5E0123C011000000000000000000000000000000000000000000000000000000000000000000000000000000FF

con questa procedura (semplificata)

procedure....ricezione
var
  Str,Nome,Val,StrElab:AnsiString;
  i,n,Posiz:Integer;
begin

Str:=ArrSckt.Sckt.RecvPacket(ArrSckt.Timeout);

StrElab:=str;
for n:=1 to Length(Str) do //converto la stringa ricevuta da char a hex
StrElab:=StrElab+IntToHex((Ord(Str[n])),2);
end;

MA LA STRINGA CHE DOVREI RICEVERE è QUESTA
5E0123C011000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000101010001010101

in sostanza dopo FF ho lo stato degli input digitali ma da li in poi non ho più nulla

pensavo al timeout troppo corto ma anche portandolo ad un secondo le cose non cambiano
oppure al fatto che le variabili di tipo stringa non possano contenere tutto quello che devo ricevere ma mi sembra molto strano
altra possibilità è che il recvpacket (Str:=ArrSckt.Sckt.RecvPacket(ArrSckt.Timeout)) non sia la scelta migliore
grazie in anticipo a tutti
Titolo: Re:Synapse e Domotica
Inserito da: xinyiman - Giugno 06, 2022, 10:38:20 pm
Se posti un sorgente da compilare e lanciare proviamo a darti una mano nel debug del problema.
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Giugno 07, 2022, 09:38:45 am
Ciao Xiny
dammi un'idea di come fare per favore perchè il sorgente completo ha i collegamenti al DB e credo che senza le schede a cui connetterti sia difficile avere un'idea di quello che succede (non che non voglia mandarlo)
Ho cercato di estrapolare il codice inerente alla comunicazione TCP per chiedervi supporto, forse non sono siuscito a farvi capire il problema?
Titolo: Re:Synapse e Domotica
Inserito da: xinyiman - Giugno 07, 2022, 01:07:37 pm
Il problema l'ho capito, ma per aiutare a risolvere abbiamo bisogno di test che replichino il problema.
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Giugno 07, 2022, 03:13:55 pm
Ciao Xiny
stavo provando a scriverti il codice come mi chiedevi ma estrapolandolo e usandolo in una semplice form buttata li funziona  :-[ :-X :o
(figura di M...)
Ora provo a capire se mi perdo qualcosa nel programma passandolo da un thread all'altro
Azz..
Titolo: Re:Synapse e Domotica
Inserito da: xinyiman - Giugno 07, 2022, 04:27:32 pm
Nessuna figura stai tranquillo. Estrapolare un test che serve ad aiutare serve proprio per capire dove possa stare il problema.
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Giugno 11, 2022, 02:19:00 pm
giusto per continuare l'esplorazione sono tornato (ma lo immaginavo) ;D
ora che riceve le "stringhe" ho il problema che queste si accumulano ad ogni richiesta come da immagine
qui il codice ridotto all'osso

procedure TForm1.BT_ReqStatoClick(Sender: TObject);
var
  n,Str1:Integer;
  StrElab,str,CRC,HexString,StrChr:String;
begin
  repeat
    HexString:=Edit2.Text;
    CRC:=CalCrc16(HexString);
    HexString:=HexString+RightStr(Crc,2)+LeftStr(Crc,2);
    StrChr:='';
    n:=1;
    while n<=Length(HexString) do
      begin
        Str1:=Hex2Dec(HexString[n]+HexString[n+1]);
        StrChr:=StrChr+Chr(Str1);
        n:=n+2;
      end;
    c.SendString(StrChr);
    Str:='';
    Str := c.RecvPacket(timeout); //timeout è 200 millisecondi
    for n:=1 to Length(Str) do //converto la stringa ricevuta da char a hex
      StrElab:=StrElab+IntToHex((Ord(Str[n])),2);
    Memo1.Append('Stringa RX:'+StrElab);
    Application.ProcessMessages;
    //Sleep(1000);
  until ferma=true ;
end;     

grazie in anticipo per ogni aiuto

Dimenticavo, nel caso in cui il tutto non sia in un ciclo repeat la cosa non succede
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Giugno 12, 2022, 10:35:04 am
giusto per continuare l'esplorazione sono tornato (ma lo immaginavo) ;D
ora che riceve le "stringhe" ho il problema che queste si accumulano ad ogni richiesta come da immagine
qui il codice ridotto all'osso

    .......
    for n:=1 to Length(Str) do //converto la stringa ricevuta da char a hex
      StrElab:=StrElab+IntToHex((Ord(Str[n])),2);
   ........

grazie in anticipo per ogni aiuto

Dimenticavo, nel caso in cui il tutto non sia in un ciclo repeat la cosa non succede

la stringa "StrElab" non viene mai "svuotata" e quindi hai l'accumulo continuo.

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Giugno 12, 2022, 08:59:07 pm
ciao drago,
grazie dopo qualche prova me ne sono accorto ma il problema mi permane nel programma principale dove ci sono 10 schede (quindi 10 socket) collegate e li cominciano a sommarsi eppure la procedura è la stessa
Potrebbe essere un problema di velocità con cui vengono inviate le stringhe?
grazie
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Giugno 12, 2022, 10:38:40 pm
ciao drago,
grazie dopo qualche prova me ne sono accorto ma il problema mi permane nel programma principale dove ci sono 10 schede (quindi 10 socket) collegate e li cominciano a sommarsi eppure la procedura è la stessa
Potrebbe essere un problema di velocità con cui vengono inviate le stringhe?
grazie
Io non uso Synapse, quindi non saprei darti una soluzione. Ho usato quasi sempre Indy, a parte alcune funzionalità dove uso i socket con API del sistema operativo.

In genere, in ogni socket la lettura del buffer dati ricevuti (più o meno aggiornato all'ultimo microsecondo  :o ) genera automaticamente la sua cancellazione, quindi "accumuli" non devono esserci.

L'unica "cosa" che mi viene in mente è che nei tuoi thread ci sia qualcosa che "disturbi" Synapse.

La velocità non è un problema, almeno io non ne ho mai avuti con flussi di pacchetti continui anche a frequenze al di sotto del millisecondo, ovvio che dipende da cosa usi ... se usi un Z80 magari si, la velocità può essere un problema.
Usi socket UDP o TCP ? Ambiente Windows, Linux o altro ? Versioni di Lazarus e FPC ?

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: xinyiman - Giugno 13, 2022, 11:22:47 am
Se il problema è l'accumulo, ti consiglio di fare una prova. Fai mandare ai dieci socket dei pacchetti strutturati come
[SCN-000001]
[SCN-000002]
...
[SCN-00000N]

Dove SCN è l'identificativo del socket SC0, SC1, SC2 ecc
mentre per il progressivo si tratta del progressivo del singolo socket.
Guarda cosa ricevi e identifichi il problema. So che è scomodo, ma almeno puoi fare debug e tarare lo strumento.
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Giugno 13, 2022, 08:33:35 pm
Drago e Xiny grazie
ho poco tempo in questi giorni ma cerco di fare qualche prova e vi saprò dire
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Giugno 18, 2022, 02:18:26 pm
Ho fatto diverse prove un po' come mi avevate detto e sono giunto alla conclusione che:

la scheda è configurata come server e quindi di suo invia le stringhe ad ogni cambio di stato degli I/O se in quel preciso momento chiedo manualmente lo stato delgi I/O le stringhe si accodano altrimenti le stringhe arrivano correttamente
Non so se questo è da considerarsi corretto dal punto di vista della scheda che utilizzo ma da quel che vedo sembra proprio cosi, non credo siano problemi di synapse o di lazarus
Drago scusami l'ultima volta non ti ho risposto, uso socket TCP, Windows 10, Lazarus 2.2.0 e FPC 3.2.2
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Giugno 18, 2022, 10:06:24 pm
Allora il problema potrebbe essere la logica.

Normalmente un server non agisce in autonomia, o agisce usando due canali.

Un Server agisce in risposta ad un preciso comando, e quando ad ogni "comando" (o interrogazione) è necessaria una sua risposta occorre fare attenzione ai flussi che sono già in opera. L'esempio tipico è un server che "streamma" e che sullo stesso canale invia anche le "risposte ai comandi.
Suddividere i dati di flusso dalle risposte non è così semplice e scontato, tanto che normalmente queste tipologie di server usano due canali: uno per il flusso e uno per i comandi.

L'alternativa è impachettare i dati con una intestazione (tipo di pacchetto e sua lunghezza) necessaria a distinguere i vari flussi contemporanei (contemporanei si fà per dire ovviamente).

Come dici tu non c'è un vero e proprio "bug": manca  il coordinamento tra le comunicazioni.

Sono convinto che la risoluzione ora che sono state capite le problematiche sarà agevole. Una abbastanza semplice è il leggere i dati per blocchi, immagino che la lunghezza si fissa e che quindi si possa usare quella per gestire le letture anche se "accodate".

Ciao ciao.
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Giugno 19, 2022, 10:17:30 pm
Drago grazie come sempre.
un consiglio, è meglio ache ogni soket(e quindi ogni dispositivo) abbia una porta diversa o è indifferente?
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Giugno 20, 2022, 10:56:52 pm
Come dissi, non conosco Synapse, ma le caratteristiche di un socket sono comuni a tutti i componenti.

Sia i client TCP che i server TCP (come anche gli UDP) hanno la possibilità di sapere da che socket remoto (IP e Porta) arrivano i dati, quindi anche con un solo socket puoi tranquillamente rilevare i dati, perchè interrogando le sue proprietà puoi identificare la fonte.

Anche la velocità non è un problema (con un solo socket riesco a gestire flussi non compressi di decine di immagini da decine di megabyte).

Poi dipende dalla logica del tuo programma.

Ti faccio un esempio banale con Indy:

Codice: [Seleziona]
//Evento ricezione dati da socket UDP comune a tutte le schede remote
procedure TCardComm.fIdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var z: cardinal;
     fLastPeerIP: string;
     //fLastPeerPort: word;
     fLastData: TIdBytes;
begin
  //incrementa un contatore interno per diagnostica
  InterlockedIncrement64(fContatore);
  try
    //Rileva l'IP Remoto di connessione
    fLastPeerIP := ABinding.PeerIP;
    //Rileva la PORTA Remota (non è di interesse)
    //fLastPeerPort := ABinding.PeerPort;
    //Legge i dati ricevuti (e automaticamente svuota il buffer di ricezione)
    fLastData := AData;
    z := 0; //Tiene conto della corsia (un sensore per corsia)
    {$IFDEF DEBUG}
      if fLastPeerIP = '127.0.0.1' then
        begin
          z := 0;
        end
      else
    {$ENDIF}
    if fLastPeerIP = '192.168.137.11' then
      begin
        z := 0;
      end
    else
      if fLastPeerIP = '192.168.137.12' then
        begin
          z := 1;
        end
 ......
   Assegna i dati (FLastData) a qualche contenitore indicizzato da Z ed elabora, oppure li usi negli altri Thread

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Luglio 19, 2022, 01:45:46 pm
Ciao Drago
una curiosità visto che mi sembra tu utilizzi molto la gestione dei socket per quella tipologia di "lavoro" che sto provando a realizzare
A livello proprio di logica di programmazione, io utilizzo il form principale per gestire la grafica (luci accese/spente, porte finestre aperte/chiuse, ec..),poi ho un thread che gestisce "l'ascolto" e ricezione delle "stringhe" dai dispositivi(che sono 10 server TCP/IP) e le smista ad un altro thread che le elabora e invia le risposte ai server, in più ho un altro thread che invia dei comandi MODBUS (sono 8 dispositivi modbus rtu collegati ad un convertitore rs845/TCP) , secondo la tua esperienza potrebbe essere una gestione corretta ?
A livello di velocità non sono proprio contento e sono convinto che il processo inerente al modbus rallenti molto
grazie in anticipo

Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Luglio 19, 2022, 08:06:35 pm
Ciao, io come te uso dispositivi di campo che usano sia seriali 485 (a 1 Mbit) che modbus TCP (senza convertitori).

La logica dei Thread mi pare corretta, e se usi i componenti corretti non dovresti avere "buchi" sulle prestazioni.

Per quello che riguarda il modbus TCP (sia esso diretto che tramite convertitori con finali RTU), l'importante e che usi socket non bloccanti, oppure in alternativa usi un componente (per esteso un socket) per ogni dispositivo.

Su rete Ethernet da 100 Mbit, purtroppo i dispositivi industriali sono ancora alla Fast Ethernet, io interrogando via modbus TCP una periferica modbus (in questo caso PLC con modbus TCP hardware integrato) ho tempi di risposte (inteso tra l'invio comando e la ricezione risposta) intorno ai 2 o 3 millisecondi. Con altri dispositivi, dove ci sono convertitori di mezzo o non sono modbus hardware, difficilmente riesco a raggiungere velocità inferiori ai 80 ms. (in modo costante, diciamo facendo i test con 1000 invii / ricezioni).

In TCP il numero di dati che scambi è ininfluente sulla velocità, in RS485 (o RS232) il tempo di scambio dipende dal numero di dati che scambi e dalla velocità ... se hai una rete a 100 Mbit, ma la seriale del dispositivo è a 38400 baud (cioè 0,0384 Mbit) .... la differenza è decisamente apprezzabile.

Se vuoi, monitora i tempi con l'unità di diagnostica che allego (se non esiste già nell'ultima versione di Lazarus):
Codice: [Seleziona]
//Uso, aggiungi l'unità tra le Uses della tua Unità
Uses  Diagnostics;

//Puoi dichiarare quanti "timer" vuoi, anche come membri di classe, locali, ....
var HighTimer: TStopWatch;
.....

begin
  HighTimer := TStopWatch.StartNew;
  ...... //funzione da eseguire
  HighTimer.Stop;
  ShowMessage(fHighTimer.ElapsedMilliseconds.ToString); //In realtà puoi spingerti a misurare  multipli di 100 nanosecondi

  //Per eseguire un'altra misura
  HighTimer.Reset;
  HighTimer.Start;
  ...... //funzione da eseguire
  HighTimer.Stop;
  ShowMessage(fHighTimer.ElapsedMilliseconds.ToString);

end;

In questo modo puoi monitorare i tempi di ogni comunicazione e verificare dove stà il colle di bottiglia.
Puoi anche crearti un'array di timer, in modo da indicizzare tutte le tempistiche in un colpo solo (occhio al threading ovviamente, consiglio di utilizzare solo timer dichiarati nella propria unità).
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Luglio 20, 2022, 01:34:02 pm
Grazie della risposta
effettivamente i tempi di risposta sul Modbus sono molto superiori agli 80 ms
provo a dare un'occhiata ai tuoi suggerimenti
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Agosto 12, 2022, 01:29:16 pm
Buongiorno
ritorno sull'argomento multithreading (sperando di farmi capire  ;D)
ho il mio thread principale (chiamiamolo thread 1) in cui ho un array di record in cui vengono memorizzati dei valori di un input analogico (per l'esattezza la posizione della tapparelle di casa), questi valori vengono aggiornati dal "famigerato" thread secondario (chiamiamolo thread 2) che riceve le stringhe dalla scheda analogica via TCP/IP
Durante la movimentazione di una tapparella (poi saranno 13) viene aperto un altro thread secondario (chiamiamolo thread 3)  che controlla la posizione della tapparella andando a leggere il valore di quel record dall'array del thread principale (cioè il thread 1)
(ho scelto di aprire un nuovo thread con la speranza di riuscire a leggere la posizione esatta della tapparella per poterla fermare ad una determinata posizione , cosa che se invecefacessi nel secondo thread (cioè il thread 2) non avrei il tempo di fare perdendo la posizione di stop della tapparella all'altezza voluta quando andrei a movimentare tutte le tapparelle contemporanemente)
La domanda è:
come mai il valore analogico che vado a leggere nel thread principale (cioè il thread 1) è sempre quello corrispondente al valore nel momento in cui è stato creato il secondo thread secondario (cioè il thread 3) ?
(difficile da scrivere  ;D  ;D, forse pretendo troppo  ;D)
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 12, 2022, 01:51:51 pm
 :o

mi sono un attimo perso. Riassumo a mio modo per vedere se ho capito bene.

Thread 1 che semplicemente non fà nulla.

Thread 2 che comunica in "diretta" con le tapparelle e scrive i dati in un array aggiornandolo in tempo reale (reale ovviamente in funzione della velocità di comunicazione).

Thread 3 che monitorizza i valori dell'array per farsi i comodi suoi (ad esempio gestire un stop programmato delle tapparelle).

Tu dici che il valore dell'array che leggi  dal Thread 1 è sempre quello che leggi al momento in cui il Thread 3 inizia a monitorare l'array stesso.

Qualcosa che non và è certo, perchè se come dici tu l'array viene aggiornato SOLO dal Thread 2 allora tre sono le cose:

a) Il Thread 2 smette di comunicare e aggiornare l'array al momento in cui il Thread 3 incomincia a monitorare;

b) Qualche Thread (il 3 ?) và a scrivere nell'array;

c) L'array che leggi non è quello giusto, ovvero ci sono più istanze dell'array (ad esempio l'array è membro di tutti i Thread e per errore leggi e scrivi array diversi).

Hai provato ad esempio a non "lanciare" il Thread 3 e vedere se i dati dell'array variano correttamente ?

P.S.: come fai a visualizzare il valore dell'array? Debugger, TEdit, TMessageBox, ShowMessage, etc ...?

Ciao.
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Agosto 12, 2022, 03:14:42 pm
non ti sei perso, hai capito tutto benissimo (le mie capacità comunicative non sono cosi pessime allora  ;D)

il thread 1 (la parte grafica del programma è il principale)
nella sezione public ho dichiarato

ArrInput:array of TInput;

Tinput è un record (dichiarato in una unit a parte solo per semplicità di gestione) ed è cosi dichiarato:

type
  TInput=record
    IndxDb,IndxArr,Numero,Timer,AnValoreAttuale,AnValMax,AnValMin,AnValIntervento,AnValCampionatura,
    IndxArrDispositivo,Utilizzo:Integer; //utilizzo corrisponde al'indice della corrispondente tabella nel db
    Etichetta,IcoON,IcoOFF,Suono,IPDispositivo:String;
    Invertito,Antifurto,Digitale:Boolean;
    IndxOutComandato:array of Integer; //inserire il numero del/degli output da comandare che corrisponde all'indice dell'array
    Stato:TStato;
  end;


il thread 2 (dedicato alla comunicazione con le schede) va ad aggiornare AnValoreAttuale e non si ferma altrimenti durante il movimento delle tapparelle non potrei accendere le luci (per esempio) ma ciò non accade

nel metodo execute (estrapolo qualche riga)

FR_Main.ArrInput[IOIndx].AnValoreAttuale:=Hex2Dec(StrElab[i+2]+StrElab[i+3]+StrElab+StrElab[i+1]);
(strElab è la stringa ricevuta ed elaborata-Fr_Main è la form del thread 1 )

if TImage(FR_Main.BCP_Pianta.FindComponent('InImg'+IntToStr(IOIndx)))<>Nil then //se l'immagine è sul BCP_Pianta
begin
  TImage(FR_Main.BCP_Pianta.FindComponent('InImg'+IntToStr(IOIndx))).Repaint;
end;

(qui aggiorno la form principale facendogli colorare la tapparella a livello grafico), se il record nell'array non venisse aggiornato il repaint non mi effettuerebbe il corretto repaint del "disegno" della tapparralle ma quello funziona

il thread 3 (che viene creato e distrutto solo al movimento della tapparella)

nel metodo execute (estrapolo qualche riga)


if FR_Main.ArrInput[IOIndx].AnValoreAttuale>=TapparellaPosizStop+FR_Main.ArrInput[IOIndx].AnValCampionatura)and
           (FR_Main.ArrInput[IOIndx].AnValoreAttuale<=TapparellaPosizStop-FR_Main.ArrInput[IOIndx].AnValCampionatura)then
           begin
             TapparellaStop(IndxFinestra);
           end;

qui USANDO IL DEBUG (effettivamente non ho provato ad usare edit o altro) il valore di FR_Main.ArrInput[IOIndx].AnValoreAttuale è sempre lo stesso identico e corrisponde
(faccio una prova con una edit per verificare che abbia lo stesso problema)
IOIndx mi riulta corretto sempre da debug

spero di avere risposto a tutto  ::)
grazie intanto


Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 12, 2022, 04:01:06 pm
Ok, allora intanto un commento secco:

TUTTE LE PARTI LCL (SOPRATTUTTO LE COMPONENTI GRAFICHE E QUINDI TIMAGE INCLUSA) NON DEVONO IN ALCUN MODO ESSERE "TOCCATE" DA UN THREAD. ALMENO PER CIO' CHE E' DI MIA CONOSCENZA ... SAREI LIETO SE QUALCUNO MI CONTRADDICESSE.

QUESTO PERCHE' IN GENERALE I COMPONENTI GRAFICI NON SONO THREADSAFE.

NEL TUO CODICE, L'USO NEL THREAD della TIMAGE può generare di tutto (soprattutto problemi).

Ripartiamo da qui.

La dichiarazione ArrInput non appartiene ad un Thread ma alla tua FORM PRINCIPALE.

StrElab immagino sia una variabile globale, il cui formato viene assicurato e verificato: quando nel Thread 2 fai Hex2Dec(StrElab[i+2]
...." se ci sono caratteri diversi da quelli esadecimali il valore non viene aggiornato ovviamente perchè la funzione andrà in eccezione.

Fai molta attenzione a quello che fai: la StrElab che proviene da una elaborazione non è garantita che sia coerente quando la leggi nel THREAD 2 .... Ti faccio un esempio: se la StrElab la elabori da qualche parte e il THREAD 2 la và a leggere in maniere asincrona può essere che la StrElab sia ancora incompleta. Per fare si che la StrElab sia completa quando la leggi nel Thread 2 devi usare qualche tecnica di sincronizzazione (non ne parlo qui se no il post diventa illeggibile).

Stesso discorso vale per ArrInput: devi garantire la coerenza di TUTTI i dati interni e la sincronia (DURANTE LA SCRITTURA NESSUNO DEVE LEGGERLA, PENA UNA INCOERENZA).

Invece per quello che riguarda il debug, non sò dirti con precisione quanto sia affidabile quello di FPC, ma posso dirti che in MULTITHREADING tutti i debug che ho provato qualche problemino c'è l'avevano .... ANCHE x64DBG .....

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Agosto 13, 2022, 08:57:00 am
Ciao Drago
ero sicuro che mi avresti fatto notare la questione delle immagini nel thread esterno  ;D perchè ovviamente hai ragione e sicuramente sarà una di quelle cose che dovrò sistemare ma purtroppo per me sono tecniche che devo comprendere
StrElab come dici tu è una stringa che viene inviata dalla scheda degli input, ed ovviamente non avendoti riportato tutto il codice, non puoi sapere che faccio dei controlli sulla lunghezza  prima di elaborarla
Purtroppo da ieri non sono ancora riuscito a fare le prove che ti avevo detto ma anche io ho il dubbio che hai sollevato sulla questione della lettura e scrittura nel record ArrInput, quindi appena riesco a fare delle prove verifico
Per me che sono un "programmatore amatoriale autodidatta" certe cose sono difficili da compre e magari ne do molte per scontate che poi si rivelano l'opposto di quello che pensavo.
Giusto per avere un tuo parere, trovi corretto mettere gli array di record che "immagazzinano" i dati sullo stato degli I/O nella form principale o sarebbe meglio inserirli nel thread dove vengono elaborate le stringhe di invio e ricezione o anche da qualche altra parte?
So che forse sono domande difficili non sapendo come ho strutturato il programma ma ogni consiglio è ovviamente ben accetto
grazie
Titolo: Re:Synapse e Domotica
Inserito da: bonmario - Agosto 13, 2022, 10:14:08 am
TUTTE LE PARTI LCL (SOPRATTUTTO LE COMPONENTI GRAFICHE E QUINDI TIMAGE INCLUSA) NON DEVONO IN ALCUN MODO ESSERE "TOCCATE" DA UN THREAD. ALMENO PER CIO' CHE E' DI MIA CONOSCENZA ... SAREI LIETO SE QUALCUNO MI CONTRADDICESSE.

QUESTO PERCHE' IN GENERALE I COMPONENTI GRAFICI NON SONO THREADSAFE.

Scusa, magari ho capito male io, ma io non mi sono mai fatto problemi ad usarle. Certo, lo faccio usando le "Critical section", per evitare problemi, ma lo faccio !

Ciao, Mario
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 13, 2022, 10:58:43 am
TUTTE LE PARTI LCL (SOPRATTUTTO LE COMPONENTI GRAFICHE E QUINDI TIMAGE INCLUSA) NON DEVONO IN ALCUN MODO ESSERE "TOCCATE" DA UN THREAD. ALMENO PER CIO' CHE E' DI MIA CONOSCENZA ... SAREI LIETO SE QUALCUNO MI CONTRADDICESSE.
QUESTO PERCHE' IN GENERALE I COMPONENTI GRAFICI NON SONO THREADSAFE.
Scusa, magari ho capito male io, ma io non mi sono mai fatto problemi ad usarle. Certo, lo faccio usando le "Critical section", per evitare problemi, ma lo faccio !
Ciao, Mario

Per tutte le parti grafiche, e in generali per tutti i componenti LCL l'uso nei Thread non è consentito. L'uso delle "Crtical Section" quando fai ad esempio una operazione su una parte grafica (Form ad esempio) non ha alcun senso, visto che non può essere garantito che l'accesso alle risorse avvenga solo nella TUA Critical Section.

In generale, affinchè una qualsiasi risorsa (le più critiche sono appunto le risorse grafiche) sia protetta ha necessità di avere delle barriere PER TUTTI gli accessi che avvengano alla risorsa. Se tutti accedono tramite la stessa barriera tutto va bene, se viene effettuato anche solo un accesso senza la barriera (è ciò che accade nelle LCL) allora è assolutamente inutile usare semafori, critical section, mutex o altro.

E' per questo che non c'è soluzione all'uso delle parti grafiche nei Thread. In realtà si può usare la procedura SYNCHRONIZE dei Thread che consente di eseguire una parte del codice del Thread nel THREAD PRINCIPALE, dove è sicuro eseguire qualsiasi cosa ... sempre con le dovute accortezze ....

Ultimamente negli ambienti più moderni è possibile eseguire alcune operazioni grafiche, le più comuni, nei Thread in quanto alcuni componenti hanno incapsulato delle barriere "automatiche" all'accesso e quindi non c'è necessità che l'utente vi provveda.
NON PENSO che ciò sia stato fatto nelle LCL. Inoltre le accortezze di cui sopra possono provocare degli effetti "secondari" di non poco conto. Supponiamo che i componenti abbiano una protezione automatica, significa che se un Thread "entra" e la barriera è attiva  ... il Thread si BLOCCA sino a quando la barriera non si disattiva. E per le parti grafiche ciò vuol dire tanto tempo (alle volte decine di millisecondi).

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 13, 2022, 11:16:37 am
Giusto per avere un tuo parere, trovi corretto mettere gli array di record che "immagazzinano" i dati sullo stato degli I/O nella form principale o sarebbe meglio inserirli nel thread dove vengono elaborate le stringhe di invio e ricezione o anche da qualche altra parte?
So che forse sono domande difficili non sapendo come ho strutturato il programma ma ogni consiglio è ovviamente ben accetto
grazie

In generale la "disposizione delle risorse", inteso come vengono allocate e dove, dipende da diversi fattori. Nei sistemi dove le prestazioni devono essere estremizzate c'è anche una analisi delle allocazioni (HEAP, STACK, MEMORIA VIRTUALE, etc....) con relativo calcolo delle prestazioni di accesso.

In generale comunque si deve cercare di creare risorse il cui accesso soprattutto se condiviso, sia facilmente gestibile. Normalmente si creano classi o record "avanzati" dove vengono incapsulati gli accessi con le proprietà, in cui puoi già inserire una barriera di protezione (un semaforo o una critical section ad esempio). Il tuo array sarò privato (o strettamente privato) e l'accesso potrà avvenire solo dalle proprietà esposte.

Nel tuo caso vedrei un record avanzato definito globalmente e non membro di una Form perchè in quest'ultimo caso tieni presente che il tuo codice deve eseguire un accesso alla Form se deve usare l'array e inoltre la Form dovrà essere indicata in tutte le unità che la usano (in generale una unità dove è definito un Thread non dovrebbe avere niente a che fare con Form e altri classi grafiche).

Per i record avanzati, ti rimando al capitolo apposito: https://wiki.freepascal.org/Record (https://wiki.freepascal.org/Record)

Se hai necessità ti posso postare anche un piccolo codice.

Attendiamo news.

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Agosto 13, 2022, 01:32:26 pm
cavoli non sapevo si potessero utilizzare i record in questo modo

grazie
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 13, 2022, 04:18:31 pm
Se vuoi, qui c'è un codice che puoi usare come partenza ..... Semplicemente Crea una applicazione, poi inserisci un pulsante nella form, doppio click sia sul pulsante che sulla form e poi copia tutto il codice qui elencato (o copia a pezzi, come ritieni più opportuno).

Codice: [Seleziona]
unit Unit1;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;


const
  MAX_TAPPARELLE = 13;

type
  TInput=record
    IndxDb,IndxArr,Numero,Timer,AnValoreAttuale,AnValMax,AnValMin,AnValIntervento,AnValCampionatura,
    IndxArrDispositivo,Utilizzo:Integer; //utilizzo corrisponde al'indice della corrispondente tabella nel db
    Etichetta,IcoON,IcoOFF,Suono,IPDispositivo:String;
    Invertito,Antifurto,Digitale:Boolean;
    IndxOutComandato:array of Integer; //inserire il numero del/degli output da comandare che corrisponde all'indice dell'array
    Stato: TStato;
  end;

type
  TDati_Tap = record
    strict private ArrInput:array of TInput;
    function getArrayInput(Index: cardinal): TInput;
    procedure setArrayInput( Index: cardinal; Value: TInput);
  private
    class operator Initialize (var Dest: TDati_Tap);
    class operator Finalize (var Dest: TDati_Tap);
  public
    property Tappa[Index: cardinal]: TInput read getArrayInput write setArrayInput;
end;

type
  EDATITAPPARELLEINVALID = class(Exception);

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;
  Tapparelle: TDati_Tap;

implementation

{$R *.lfm}

{ TForm1 }

class operator TDati_Tap.Initialize (var Dest: TDati_Tap);
var i: cardinal;
begin
  SetLength(Dest.ArrInput, MAX_TAPPARELLE);
  //Qui puoi inizializzare tutti i valori dell'array
  for i:= Low(Dest.ArrInput) to High(Dest.ArrInput) do
    begin
      Dest.ArrInput[i].IndxDb:= 0;
      //etc .....
    end;
end;

class operator TDati_Tap.Finalize (var Dest: TDati_Tap);
begin
  SetLength(Dest.ArrInput, 0);
end;

function TDati_Tap.getArrayInput(Index: cardinal): TInput;
begin
  if (Index >= Low(ArrInput)) and (Index <= High(ArrInput)) then
    begin
      Result := ArrInput[Index];
    end
  else
    raise EDATITAPPARELLEINVALID.Create('Richiesta al di fuori dei limiti');
end;

procedure TDati_Tap.setArrayInput(Index: cardinal; Value: TInput);
begin
  if (Index >= Low(ArrInput)) and (Index < High(ArrInput)) then
    begin
      ArrInput[Index] := Value;
    end
  else
    raise EDATITAPPARELLEINVALID.Create('Richiesta al di fuori dei limiti');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(Tapparelle.Tappa[0].IndxDb.toString);
end;

procedure TForm1.FormCreate(Sender: TObject);
var prova: TInput;
begin
  Prova.IndxDb := 20;
  //Prova.Antifurto:= ....;
  //etc ....
  Tapparelle.Tappa[0] := Prova;
end;

end.

P.S.: Non ti ho inserito barriere di protezione, è solo per darti un là su un altro modo di gestire i dati.

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Agosto 13, 2022, 05:56:41 pm
Grazie Drago
provo a "tradurre" il tuo programma  :o ;D

sono riuscito a controllare e ti confermo che è il debug a non funzionare
Ho messo delle label e quelle si aggiornavano correttamente

credi che 13 thread non diano problemi al pc in merito alle prestazione?
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 13, 2022, 06:48:49 pm
Grazie Drago
provo a "tradurre" il tuo programma  :o ;D

sono riuscito a controllare e ti confermo che è il debug a non funzionare
Ho messo delle label e quelle si aggiornavano correttamente

credi che 13 thread non diano problemi al pc in merito alle prestazione?

No, non ci sono problemi con 13 Thread. L'unica cosa, che dipende da cosa stà facendo il computer in generale, che processore ha, RAM, etc ...., potrebbe essere  un rallentamento generale. Ma se hai un processore abbastanza recente (non un ATOM  :P ) e non fai uso di memoria SWAP, problemi non ne avrai.

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Agosto 13, 2022, 09:58:22 pm
ho un I5-7500T @2700GHz Win10 64bit- 8GB di RAM
ma si impianta di brutto brutto  ;D ;D ;D
per la serie... stacca la spina e riavvia ;D ;D ;D ;D ;D
e il pc è dedicato solo a quello ;D ;D
fino a che ne crea 7 o 8 procede bene poi comincia a rallentare molto
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 13, 2022, 11:14:22 pm
Ok. E' un processore 4 core senza Hyper Threading. Con un profilo di potenza tra l'altro bassissimo (adatto generalmente per i Tablet).

Intanto disattiva l'uso del file di paging. Se hai una memoria di 8 GB non serve. Se non sai come fare segui questo articolo e scegli NESSUN FILE DI PAGING e poi premi IMPOSTA https://www.navigaweb.net/2008/04/windows-xp-impostazione-del-file-di.html (https://www.navigaweb.net/2008/04/windows-xp-impostazione-del-file-di.html)

Devi poi riavviare.

Per usare i Thread in un processore di quel tipo non puoi fare quello che vuoi ma devi seguire alcune regole. Intanto i Thread devono occupare meno tempo di elaborazione possibile. Questo significa che per una buona parte del tempo devono stare in condizione di "sleep" o di "WAIT". Per fare ciò nel metodo Execute del Thread devi inserire  uno sleep(xxx) al temine del ciclo e non ciclare continuamente. Questo modo di mettere uno sleep è abbastanza obsoleto, ma è sempre meglio di ciclare di continuo.

La condizione consigliata (al posto dell'obsoleto sleep) è che il Thread vada in stato di WAITFOROBJECT (o simili) e rimanga in attesa (anche in modalità INFINITE).

In pratica il WAITFOROBJECT attende che un Evento venga settato e fà continuare l'esecuzione del Thread.

Un'altra ottimizzazione è quella di creare tutti i Thread che servono all'avvio della applicazione e usare quanto detto sopra invece di "creare" e "distruggere" i Thread di continuo.

Con queste accortezze, e la gestione del codice oculata non dovresti avere problemi si rallentamenti e/o blocchi.

Vedo di postarti quanto prima un esempio di quello che ho descritto.

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 15, 2022, 01:58:34 pm
Mi ero dimenticato del ns. blog  ;D : a questo link trovi qualche info tecnica ed esempio sui Thread https://blog.lazaruspascal.it/2022/04/24/thread/ (https://blog.lazaruspascal.it/2022/04/24/thread/)

Ciao
Titolo: Re:Synapse e Domotica
Inserito da: Diego1981 - Agosto 15, 2022, 11:00:57 pm

è bastato inserire uno sleep(10) per far si che funzionasse tutto
Intanto Grazie
Titolo: Re:Synapse e Domotica
Inserito da: DragoRosso - Agosto 16, 2022, 06:54:32 pm

è bastato inserire uno sleep(10) per far si che funzionasse tutto
Intanto Grazie


Però vedi di passare agli eventi, con il WaitFor ... vedrai che ti troverai decisamente meglio e inoltre il tuo programma userà CPU solo quando necessario, oltre ad avere un minimo di sincronizzazione tra le attività.

Ciao