varg Inserito: 7 novembre 2006 Segnala Inserito: 7 novembre 2006 Salve a tutti chiedevo se qualcuno di voi aveva esempi di utilizzo della DLL LibNoDave per la comunicazione tra plc Siemens e PC, in particolare dovrei interfacciarmi a un S7-200 da un PC tramite porta seriale, pertanto chiedevo se qualcuno di voi ha un esempio in Visual Basic, anche perchè nella documentazione allegata alla dll (versione 0.8.2) ho trovato ben poca roba, tra cui un presunto modulo VB che però si vede che è stato fatto per interfacciarsi con il pacchetto Office quindi lascio immaginare a voi che casino micidiale possa essere.Vi ringrazio per la disponibilità
Bruno Inserita: 12 novembre 2006 Segnala Inserita: 12 novembre 2006 CiaoSe hai un paio di giorni di pazienza metterò un esempio in VB6 nell'area download, se invece haifretta puoi controllare sul forum di libnodave su sourceforgehttp://sourceforge.net/forum/forum.php?thr...forum_id=205657un utente ha messo un esempino (richiede mySQL ma è abbastanza semplice) da cui puoiestrarre il modulo per accedere alla DLL.CiaoBR1
varg Inserita: 14 novembre 2006 Autore Segnala Inserita: 14 novembre 2006 Avevo visto anchio quell'esempio infatto l'ho scaricato e a tempo perso "lavoro permettendo" lo sviscero...Comunque ho notato che stai facendo un Esempio in VB6 perfetto se serve una mano in qualche modo mi offro. Almeno mi auguro che questo esempio possa diventare un aiuto per tutti, Me compreso.Chiedo una cosa il tuo esempio a cui stai lavorando su che plc e che tipo di connessione si basa ?
Bruno Inserita: 14 novembre 2006 Segnala Inserita: 14 novembre 2006 Ho appena messo l'esempio nell'area up-download files sezione Home-Visual Basic.E' la prima realese di un software didattico (deve essere semplice non deve essere pensato per un impianto),è pensato per connettersi ad un PLC per volta e basta, utilizzando una delle seguenti modalità:PG adapter Seriale per S7-300 - MPI for S7 300/400PG adapter Seriale per S7-300 - MPI for S7 300/400, "Andrew's version"PG adapter Seriale per S7-300 - MPI for S7 300/400, Step 7 Version, not yet implementedPG adapter Seriale per S7-200 - PPI for S7 200 (utilizzare baud-rate 9600) (non testato in quanto mi manca PLC)Adattatore Seriale per S5 - S5 via programming interface (non testato in quanto mi manca PLC)Interfaccia PG-PC Siemens - S7 using Siemens libraries & drivers for transportScheda Ethernet - ISO over TCP - MPI with IBH NetLink MPI to ethernet gateway - PPI with IBH NetLink PPI to ethernet gatewayI metodi di collegamento in grassetto sono stati testati, gli altri sto aspettando l'occasione.Per quanto riguarda la modalità ISOonTCP ho una dozzina di impianti funzionanti senza problemi, gli altri sono test in laboratorio ma con successo.Se notate qualcosa contattatemi pure attraverso PLC Forum o all'indirizzo **[at]**[dot]it, fra poco (ho già un progetto funzionante) pubblicherò un esempio stand-alone sviluppato in C# (utilizzo framework 2.0 e come IDE SharpDevelop e Visual C# Express 2005).BR1
Bruno Inserita: 14 novembre 2006 Segnala Inserita: 14 novembre 2006 Dimenticavo nel caso di S7-200 il numero DB deve essere messo a 1....ciao
varg Inserita: 14 novembre 2006 Autore Segnala Inserita: 14 novembre 2006 Perfetto, siccome dispongo di un S7 200 Con Protocollo PPI provvedo a testare io e ti so dire qualcosa.
tavazzi Inserita: 15 novembre 2006 Segnala Inserita: 15 novembre 2006 Ciao Bruno, credo di aver chattato con te un po' di tempo fa' a proposito di un discorso simile : comunicazione Pc-PLC via rete usando il protocollo Fetch-Write e usando Delphi sul lato PC. Avevo usato un tuo esmpio Visual Basic e tutto e' andato a buon fine. Mi e' rimasta pero' la curiosita' di capire se quella strada era realmente vantaggiosa rispetto a ProDave (anche perche' credevo che questo non andasse con Ethernet, mentre invece scopro il contrario). Hai fatto qualche valutazione/test su quantita' dati scambiabili, affidabilita', complessita', ecc. ?. Ciao e grazie in anticipo, Sergio Tavazzi
Bruno Inserita: 15 novembre 2006 Segnala Inserita: 15 novembre 2006 CiaoMi ricordo dello scambio di informazioni fatte...Per quanto riguarda ProDave si funziona anche in Ethernet (solo dall'ultima release la 6.0), ma io non l'ho abbracciata in quanto per installarlo devi pagare il pacchetto runtime (uno per ogni installazione !)L'esempio in questione utilizza le librerie LibNoDave (che non sono Siemens !!!) che sono opensource e rilasciate sotto licenza LGPL per cui puoi sviluppare in tuo protocollo e installarlo come vuoi.Come detto anche in altri messaggi è che oltre alla tipologia di licenza tu puoi preparare un protocollo di comunicazione che funziona con diversi tipi di PLC (S5, S7-200, S7-300) e diversi tipi di interfaccia.Per quanto riguarda limitazioni: il pacchetto base della Siemens non può essere più lungo di 220 byte, ma nessuno ti vieta di preparare funzioni (tipo ReadPLC o WritePLC) che si occupano dello spacchettamento e rincompattamento dei messaggi.La funzionalità del protocollo Fetch/Write (che era nato per S5) è limitato a scambi di word (e non byte) e richiede una configurazione sul lato PLC (abilitare il protocollo e configurare le porte socket per la connessione), nella modalità Ethernet ISOonTCP puoi accedere sia a Byte che a Word e non si richiede nessuna consifurazione sul PLC (il protocollo è sempre abilitato e la porta socket è la 112).Spero di essere stato chiaro.CiaoP.S.Fate attenzione LibNoDave NON è Prodave, quest'ultimo è un pacchetto Siemens con autorizzazione da comperare e consegnare con il software al cliente!!!
tavazzi Inserita: 15 novembre 2006 Segnala Inserita: 15 novembre 2006 Chiarissimo, ma' hai anche potuto valutare la quantita' max di dati (bytes o words, non importa) scambiabili x secondo ?. Ciao e grazie, Sergio Tavazzi
Bruno Inserita: 15 novembre 2006 Segnala Inserita: 15 novembre 2006 Naturalmete le tempistiche dipendono dal tipo di collegamento (Interfaccia seriale, interfaccia USB, CP integrata, Ethernet) e se tieni sempre aperta la connessione o se la chiudi e la riapri ogni volta.Nell'esempio che trovi nel sito (quello sopra citato), visualizzo il tempo (in millisecondi) dell'operazione eseguita (un esempio tra i 70 e 90 msec per leggere 150 bytes via ethernet dalla mia postazione al PLC passando per tre switch in cascata).Ho fatto delle prove con il PLC virtuale della Siemens ed è stato molto bello (velocissimo).Fammi sapere se le prove ti vanno a buon fine.Per Varg se riresci a provare con S7-200 fammi sapere se funziona, per gli altri in settimana mi arriva un S5 e vi saprò dire se leprove sono OK.BR1
varg Inserita: 16 novembre 2006 Autore Segnala Inserita: 16 novembre 2006 S7-200 Collegamento PPIConnessione: OKStop: OKRun: OKProvato a leggere DB (Byte): OKProvato a scrivere DB (Byte): OKProvato a leggere DB (Byte) + Elementi: OKFaccio altre prove appena possibile.Saluti
Bruno Inserita: 16 novembre 2006 Segnala Inserita: 16 novembre 2006 Grazie Varg dei test....scusami non ho capito la dichiarazione:Provato a leggere DB (Byte) + Elementi: OKcosa intendi ?Ciao
varg Inserita: 17 novembre 2006 Autore Segnala Inserita: 17 novembre 2006 Si scusami, intendevo che ho provato ad aumentare il campo elementi per ricevere in un unico colpo più DB appena riesco faccio un paio di test anche per i Merker
Adriano71 Inserita: 27 novembre 2006 Segnala Inserita: 27 novembre 2006 X Bruno,scusa se non ho capito bene, ma hai scritto che con protocollo S5 su TCP/IP c'e' una limitazione a 220 byte.Ebbene, io e' parecchio tempo che uso C# 2005 Express in connessione con piu' socket asincroni verso CP343Lean e la limitazione non esiste, ossia:1. alla richiesta la CP343 ti risponde con un pacchetto lungo non piu' di 220 byte.2. dopo averli letti, rilancio una chiamata callback per leggere i restanti.Io normalmente leggo anche 10Kbyte su DB con una sola richiesta.Se vuoi info fammi sapere.Saluti
Bruno Inserita: 27 novembre 2006 Segnala Inserita: 27 novembre 2006 Forse non mi ero spiegato bene...la limitazione a cui mi riferivo era sul pacchetto usato nelle librerie LibNoDave, mentre immagino che tu ti riferisca al protocollo Fetch/Write, che comunque anch'esso in passato aveva una quantità limitata di BYTE per ogni scambio (superata con schede che permettevano i messaggi lunghi).Non penso che sia possibile la lettura di messaggi lunghi 10KB con il pacchetto dati di LibNoDave.Toglimi una curiosità: cosa in tendi per "rilancio una chiamata callback per leggere i restanti" ? Controlli il buffer del socket via polling o ti alzi un evento ?CiaoBR1
Adriano71 Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Scusa x il ritardo, ma ero ad una messa in servizio...Dunque, io utilizzo C# 2005 Express, e mi sono generato due classi. Una per leggere ed un'altra per scrivere (su plc Fetch/write).Per quanto riguarda la lettura, passo indirizzo e poi avvio la lettura ciclica, ossia:1. la S7Read, prima apre connessione a socket remoto.2. se connessione ok, lancia richiesta di lettura dati e genera funzione di callback (così chiamata in C#, simile ad evento).3. quando il callback mi risponde, se dati validi, controllo lunghezza buffer. Se buffer.lenght minore della richiesta, memorizzo lunghezza attuale e buffer dati, dopodiche rilancio chiamata callback. (in questo modo non appena mi arrivano i restanti, riesegue il punto 3 fino ad ottenere lunghezza richiesta). Se buffer.lenght uguale lunghezza richiesta, analizzo intestazione messaggio S5.4. dopo lettura valida, ho un eventuale timer per ritardo nuova richiesta di lettura, oppure rilancio immediatamente la chiamata ad un'altra lettura.In questo modo, da plc mi copio in un DB tutti i dati che il pc deve leggere (es. 2kb)Ad avvio software PC inizializzo come da procedura sopra, e la classe indicata, mi genera un evento quando ha letto tutti i dati. Poi automaticamente si rilancia.NO, non utilizzo il pooling, in questo modo il PC è libero di gestire la grafica e l'HMI.La classe write, è ancora più bella, lancio la funzione di inizializzazione con indirizzo, porta, blocco dati, lunghezza e array di byte, e la classe mi rilancia un evento di stato fine scrittura.Se ne lancia per esempio 10 in contemporanea, automaticamente ne lancia uno dopo l'altro.Se ti interessa, posso fare un copia ed incolla della classe read e write.Saluti Adriano
tavazzi Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Scusa se mi intrometto, ma a me quel copia e incolla interesserebbe molto ... . Mi piacerebbe anche capire qual'e' il rendimento effettivo di tutto il marchingegno. Per es. se mi dici che trasferisci 2 k (supponiamo in ambo i sensi), quante volte riesci a farlo al minuto ? ogni altro esmpio e' benvenuto purche' si riesca a quantificare un po' la resa del sistema. Grazie in anticipo, Sergio
Adriano71 Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 (modificato) QUESTA e' la classe S7SockerRDClassPiu' avanti trovate come richiamarla dal supervisoreusing System; using System.Collections.Generic; using System.Text; using System.Net; using System.Net.Sockets; namespace xxxxxx { public delegate void S7SocketRDEvent(object sender,byte nDB,int Offset,int nByte, byte[] Values); public delegate void S7SocketStateEvent(object sender,byte nDB,int Offset,int nByte,bool Stato,int ID); public struct SocketData { public int Lunghezza_Richiesta; public int Lunghezza_Attuale; public byte[] buffer; } class S7SocketRDClass { #region Variabili public event S7SocketRDEvent S7DataIncoming; public event S7SocketStateEvent S7StateChange; IAsyncResult m_result; public AsyncCallback m_pfnCallBack; public Socket m_clientSocket; public byte[] Values=new byte[2050]; public int lunBuff; public bool OK; public bool iConnected = false; public bool Disconnect; public byte nDB; public int OffsetDB; public int nByte; int nWord; public SocketData Ricezione; byte[] fetchResponse=new byte[11]; public bool iEnable_Delay = false; public bool Busy = false; public int ID; public string ipAddr; public string portNumber; #endregion #region Timer System.Timers.Timer timer1 = new System.Timers.Timer(1000); public void InitTimer() { timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Elapsed); timer1.AutoReset = true; timer1.Enabled = false; } public void TimerDelay(int interval) { timer1.Interval = interval; } void timer1_Elapsed(object source, System.Timers.ElapsedEventArgs e) { timer1.Enabled = false; WaitForData(); } public void EnableTimer(bool Stato) { timer1.Enabled = Stato; } public bool Enable_Delay { get { return iEnable_Delay;} set { iEnable_Delay = value; if (iEnable_Delay & Connected & !Busy) { InitTimer(); WaitForData(); } } } #endregion #region Gestione connessione public void CloseConnection() { //Termina la connessione e distrugge il socket if (m_clientSocket != null) { m_clientSocket.Close(); m_clientSocket = null; Connected = false; } } public void OpenConnection(string IPAddr, string PortNumber) { Ricezione.buffer = new byte[9999]; //Apre la connessione creando il socket //Se non ho passato tutti parametri, sospendo if (IPAddr == "" || PortNumber == "") { Connected = false; return; } ipAddr = IPAddr; portNumber = PortNumber; try { //Creo istanza al socket m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //Converto indirizzo IP e numero porta IPAddress ip = IPAddress.Parse(IPAddr); int iPortNo = Convert.ToInt16(PortNumber); //Creazione ENDPOINT IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo); //Imposto timeout //Creo connessione con EndPoint m_clientSocket.Connect(ipEnd); //Verifico se connesso if (m_clientSocket.Connected) { Connected = true; WaitForData(); } else { Connected = false; } } catch (SocketException) { Connected = false; } //Inizializzo i valori del fetchResponse buffer fetchResponse[0] = 83; fetchResponse[1] = 53; fetchResponse[2] = 16; fetchResponse[3] = 1; fetchResponse[4] = 3; fetchResponse[5] = 6; fetchResponse[6] = 15; fetchResponse[7] = 3; fetchResponse[8] = 0;//0 se nessun errore fetchResponse[9] = 255; fetchResponse[10] = 7; } #endregion #region CallBack e classe SocketPacket void WaitForData() { try { Busy = true; Invia(); if (m_pfnCallBack == null) { m_pfnCallBack = new AsyncCallback(OnDataReceived); } SocketPacket theSocPkt = new SocketPacket(); theSocPkt.thisSocket = m_clientSocket; m_result = m_clientSocket.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, m_pfnCallBack, theSocPkt); } catch (SocketException) { Connected = false; } } public class SocketPacket { public Socket thisSocket; public byte[] dataBuffer = new byte[2050]; } public void Invia() { try { Ricezione.Lunghezza_Attuale = 0; Ricezione.Lunghezza_Richiesta = nByte; nWord = nByte / 2; byte[] buffByte = new byte[16]; //Creazione messaggio S5 (16 byte) buffByte[0] = 83; buffByte[1] = 53; buffByte[2] = 16; buffByte[3] = 1; buffByte[4] = 3; buffByte[5] = 5; buffByte[6] = 3; buffByte[7] = 8; buffByte[8] = 1; buffByte[9] = nDB; buffByte[10] = Convert.ToByte(OffsetDB / 256); buffByte[11] = Convert.ToByte(OffsetDB % 256); buffByte[12] = Convert.ToByte(nWord / 256); buffByte[13] = Convert.ToByte(nWord % 256); buffByte[14] = 255; buffByte[15] = 2; if (m_clientSocket != null) m_clientSocket.Send(buffByte); else Connected = false; } catch (SocketException) { Connected = false; } } public void OnDataReceived(IAsyncResult asyn) { try { //Attivo il socket ID SocketPacket theSockId=(SocketPacket)asyn.AsyncState; //Termino lettura e leggo numero di byte ricevuti int iRx=theSockId.thisSocket.EndReceive(asyn); if (iRx + Ricezione.Lunghezza_Attuale != Ricezione.Lunghezza_Richiesta + 16) { Values = theSockId.dataBuffer; Array.Copy(Values, 0, Ricezione.buffer, Ricezione.Lunghezza_Attuale, iRx); Ricezione.Lunghezza_Attuale += iRx; m_result = m_clientSocket.BeginReceive(theSockId.dataBuffer, 0, theSockId.dataBuffer.Length, SocketFlags.None, m_pfnCallBack, theSockId); return; } else { Values = theSockId.dataBuffer; Array.Copy(Values, 0, Ricezione.buffer, Ricezione.Lunghezza_Attuale, iRx); Ricezione.Lunghezza_Attuale += iRx; } lunBuff=Ricezione.Lunghezza_Attuale; if (lunBuff == nByte + 16) { Values = Ricezione.buffer; OK = true; //Controllo con fetchResponse for (int i = 0; i < 11; i++) { if (fetchResponse[i] != Values[i]) { OK = false; } } } else { OK = false; } if (OK) { byte[] V=new byte[nByte]; Array.Copy(Values, 16,V,0,nByte); S7DataIncoming(this, nDB, OffsetDB, nByte, V); } if (Disconnect) { CloseConnection(); Disconnect=false; } else { if (iEnable_Delay) { timer1.Enabled = true; } else { WaitForData(); } } } catch (SocketException) { Connected=false; } Busy = false; } #endregion public bool Connected { get { return iConnected; } set { iConnected = value; S7StateChange(this, nDB, OffsetDB, nByte, iConnected,ID); } } } } Questi invece le procedure da seguire per richiamare la classe S7SocketRDClass[] s7SK = new S7SocketRDClass[6]; //Dichiarazione di 6 differenti socket indicizzati Inizializzazione.... mostro solo quella con indice 0 for (int i = 0; i < 5; i++) { s7SK[i] = new S7SocketRDClass(); //Eventi che vengono richiamati quando ricevo dei dati validi, o quando lo stato passa //da Online a Offline s7SK[i].S7DataIncoming += new S7SocketRDEvent(s7Socket_S7DataIncoming); s7SK[i].S7StateChange+=new S7SocketStateEvent(s7Socket_S7StateChange); } s7SK[0].nDB = 103; s7SK[0].OffsetDB = 0; s7SK[0].nByte =1220; //Numero di byte da leggere s7SK[0].InitTimer(); s7SK[0].TimerDelay(100); if (ipPLC == "127.0.0.1") s7SK[0].Enable_Delay = true; else s7SK[0].Enable_Delay = false; s7SK[0].ID = 1; s7SK[0].OpenConnection(ipPLC, "2000"); Se la variabile Enbled_Delay e' TRUE, al termine di una lettura attende il ritardo TimerDalay(ms) e ne rilancia un'altra. Se FALSE, appena finita la lettura, ne rilancia un'altra. Evento lanciato quando ho dei dati in lettura PS: siccome l'evento appartiene ad un diverso thread rispetto al form che lo intercetta, prestare attenzione a generare errori di cross-thread quando si aggiorna la grafica. Per info, se si genera errore vedere . di C# private void s7Socket_S7DataIncoming(object sender, byte nDB, int Offset, int nByte, byte[] Values) { switch (nDB) { case 101: //Dati ciclo plc.DB101.Valori = Values; break; case 102: //Dati macchina plc.RiempiDB102(Values); break; case 103: //Letture plc.RiempiLetture(Values); break; case 104: //Funzioni plc.DB104.Valori = Values; break; case 107: //Allarmi plc.RiempiAllarmiRes(Values); break; } } Eventi lanciato in caso di variazione ONLine - OFFLine private void s7Socket_S7StateChange(object sender, byte nDB, int Offset, int nByte, bool State,int ID) { //State=true ==> ONLINE //State=false ==> OFFLINE } Ricordate di nel FormClosed di mettere s7SK[0].Disconnect = true;Per quanto riguarda la tua domanda, ti confermo e' tranquillamente possibile eseguire letture di blocchi di 2kb al piu' in 1/10 sec. (in WiFi ottieni un valore simile)Nel mio protocollo non ho preso in considerazione la lettura di M, E, A, ecc. SOLO DBPC utilizzato: P4 512Mb scheda ethernet 100mb. PLC CPU3152DP (versione 2AG10) e CP343-LeanSeguira' classe di scrittura verso PLC Modificato: 30 novembre 2006 da Gabriele Corrieri
Adriano71 Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Dimenticavo, il numero di DB non puo' essere superiore a 255!Nella 343 impostare come tempo di keep alive il valore di 10secondi.Se si arresta il programma, aspettare almeno 10 secondi per rilanciarlo, in quanto la CP343 deve far "cadere" le connessioni precedenti.
tavazzi Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Veramente notevole .. .Dimmi una cosa : le connessioni aperte sono sempre 2 (Fetch e Write), oppure come mi e' parso di capire, sono 6 come i sockets ? forse la domanda puo' sembrare stupida, ma preferisco chiarire bene tutto. Ciao , Sergio
Adriano71 Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Io nel PLC ho aperto 6 connessioni in FETCH dalla porta 2000 alla 2005. Per quanto riguarda le Write ne uso 1 sulla porta 3000
Adriano71 Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Scusa, ma sono un po' imbranato con i forum, e dopo aver dato l'invio mi ricorda qualcos'altro.Ebbene, io nel PLC leggo sempre 6 DB da DB101 a DB106.Nella DB103 ho i valori di quote, tempi stati ecc. che mi occorrono abbastanza spesso (aggiornate almeno 5 volte al secondo), quindi imposto la classe per funzionare senza ritardi (vedi appunto precedente)Le altre DB invece le imposto con ritardi differenti (per esempio la lettura degli allarmi la eseguo ogni secondo).Siccome tutte le classi mi generano lo stesso evento, una volta lanciate (openconnection) quando ricevo l'evento leggo il numero di DB e copio i valori nell'array appropriato.Nel resto del programma poi mi vado a leggere i valori direttamente nell'array (gli array anno lo stesso nome del DB: es. byte[] DB103=new byte[2048]Per girarti tutti i byte (da cpu PLC a INTEL) utilizzo la classe Marshal.
Adriano71 Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 E' comparsa una faccina nel messaggio, volevo scrivere "puntoevirgola", "parentesichiusa"
Bruno Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Ciao Ho visto il codice e immaginavo che usassi il protocollo FETCH/WRITE (sempre ottimo), anche io l'ho usato per un po', ma al momento sono stato attratto dalle librerie LibNoDave.Ti consiglio di testarle (se le scarichi dal sito vi trovi anche un esempio in C# e funzionano), a prima vista potrebbe sembrare un poco più complesso ma hanno i loro vantaggi:1) Non necessitano di nessuna configurazione sul PLC (non male quelle volete che vuoi leggere dati su un altro PLC)2) Con lo stesso protocollo riesci a gestire diversi hardware (es: Ethernet e MPI)comunque posta anche l'altra classe, lo scambio del software è sempre una cosa molto valida.(Al massimo puoi mettere l'esempino nell'apposita area)CiaoBR1
Adriano71 Inserita: 30 novembre 2006 Segnala Inserita: 30 novembre 2006 Scusa, ma sono un novello del forum, come faccio ad allegare dei file?
Messaggi consigliati
Crea un account o accedi per commentare
Devi essere un utente per poter lasciare un commento
Crea un account
Registrati per un nuovo account nella nostra comunità. è facile!
Registra un nuovo accountAccedi
Hai già un account? Accedi qui.
Accedi ora