Rxtx e chiusura connessione da Eclipse...

Ciao!

recentemente sto portando avanti il discorso Arduino.
Ho un problema relativo all'rxtx.

Tramite il playground ho allestito l'environment java e arduino per una semplice comunicazione.

lato arduino...una cosa facilissima:

void setup(){
  Serial.begin(9600); 
}

void loop(){
   Serial.println("test connessione ok!");
      delay(1000);
      Serial.println("Locking....");
      Serial.end();
      Serial.flush();
   // while(1){} 
}

Purtroppo sebbene funzioni, non riesco a capire come fare in modo che il progetto in eclipse non rimanga in Hang.
Il comando per leggere il chunk da arduino:

while(oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			
			try {
				int available = input.available();
				System.out.println(available);
				byte chunk[] = new byte[available];
				input.read(chunk, 0, available); 
				// Displayed results are codepage dependent
// 		  while(input.available()>0) {
		 
				System.out.print( new String(chunk)); 
	 
			   
			} catch (Exception e) {
				this.close();
				System.err.println(e.toString());
			}
		}

Non è in grado di capire quando non esistono + bytes o che il chunk rimane vuoto per interrompere il while.

Ho dovuto persino commentare input.available()o non mi avrebbe restituito mai nessun dato da sysout...

Aggiungo che dopo qualche tentativo mi becco pure su Eclipse un:

Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
Could not find COM port.

E l'unico modo per uscirne è spegnere e riavviare l'IDE!! assurdo!!

grazie!

ciao,
devi usare un approccio ad oggetti.

La classeSerial di RXTX può avere un listener, ovvero una classe che implementa un'interfaccia che dice che azioni si vogliono allo scatenarsi di un evento.

Quindi puoi creare una classe che implementa SerialPortEventListener, così facendo quella classe sarà costretta ad avere il metodo

@Override
	public void serialEvent(SerialPortEvent arg0) {[...]}

ovvero una funzione che viene chiamata all'arrivo dei dati. Il punto è che questa funzione viene chiamata da un Thread esterno, duinque entriamo nel mondo del parallelismo che con arduino non esiste.

velendo anche il tuo approccio va bene, basta che metti la parte che ascolta in un altro thread.

Occhio però che poi che la variabile usata per "portare" i dati dall'evento al resto del codice và sincronizzata.

E l'unico modo per uscirne è spegnere e riavviare l'IDE!! assurdo!!

rimane aperto il programma in ascolto della COM. Sicuro di aver ciuso il tuo programma (sotto, dove c'è la consolle, ci dovrebbe essere un tasto rosso quadrato, premilo e riprova)

Ciao!!

anzitutto grazie per l'attenzione.
Ti dirò, colpa mia che ho omesso il codice.
In realtà la classe che uso già implementa SerialPortEventListener, e il codice che ho incollato al mio primo intervento in realtà è racchiuso nel metodo del listner:

public synchronized void serialEvent(SerialPortEvent oEvent) {
		
		while(oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			
			try {
				int available = input.available(); 
				byte chunk[] = new byte[available];
			        input.read(chunk, 0, available);  
				System.out.print( new String(chunk));  
			} catch (Exception e) {
			this.close();
				System.err.println(e.toString());
			}
		}  
	}

La tua frase finale era proprio ciò che sospettavo. Il listner non è in grado di stabilire se il flusso dei dati è terminato e quindi il progetto non si stoppa.
Il punto focale sta proprio nella lettura dei dati.
In realtà ho cercato di influenzare in mille modi la lettura ciclica della COM per riuscire a capire come chiudere produttivamente l'ascoltatore ma non ci riesco.

Il while iniziale con SerialPortEvent.DATA_AVAILABLE non si disabilita quando terminano le sysout da parte di arduino.
Ho provato a stampare il valore ottenuto dall'input read e ho notato che quando è "fermo" restituisce -1.
Tuttavia aggiungendo una cosa simile:

try {
			 int available = input.available(); 
			 byte chunk[] = new byte[available];
			 input.read(chunk, 0, available);   
   	                 while(input.available()>-1) { 
				System.out.print( new String(chunk)); 
   			 } 
  			input.close();
  			close();
			} catch (Exception e) {
			this.close();
				System.err.println(e.toString());
			}

Il risultato è una stampa nella console di java di caratteri incomprensibili, e successivamente rimane in hang di nuovo.

metodo che uso per "chiudere"

public synchronized void close() {
		if (serialPort != null) {
			serialPort.removeEventListener();
			serialPort.close();
		}
	}

dove sbaglio?

grazie!

mi sa che la chiamata che usi è bloccante, e fa casino perchè ricevi più serialEvent per la stringa, ma magari lggi tutto al primi serial event rimaendo bloccati negli altri.

Infatti nella comunicazione seriale OGNI BYTE di dati è una comunicazione a sè. E' per questo che la seriale non può chiudersi da sola, e anche se arduino chiudesse la connessione, il pc non potrebbe accorgersene perchè non viene inviato un comando apposito (al contrario, invece, arduinino si resetta se non disattivi l'autoreset, se lo disattivi siamo alla stessa situazione del pc). Quindi la Serial.end() non funziona, devi inviare uno o più simboli per avvisare l'altra parte della chiusura.

while(input.available()>-1) { 
				System.out.print( new String(chunk)); 
   			 }

questo codice non ha senso.

una volta che hai COPIATO il buffer della seriale in chunk, non ti serve più avere informazioni sulla seriale, perchè a tutti gli effetti è una cosa completamnte scollegata.
Ho notato che qualcosa di simile c'è anche nel primo post, ma non in quello quà sopra:

while(oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			
			try {
				int available = input.available(); 
				byte chunk[] = new byte[available];
			        input.read(chunk, 0, available);  
				System.out.print( new String(chunk));  
			} catch (Exception e) {
			this.close();
				System.err.println(e.toString());
			}
		}

questo mi pare corretto, ed è simile a quello che uso io (il mio è java e usa un buffer tmp per leggere non più di un tot di dati alla volta, ma è una questione tecnica):

if (input.available() > 0) {
int len = input.read(tmp);

System.out.println("readed: "+len);
byte[] outTemp = new byte[len];
System.arraycopy(tmp, 0, outTemp, 0, len);

Grazie alle tue preziose indicazioni ci sono riuscito!

Questa discussione mi è tornata davvero utile ora che sto gettando le basi per conoscere Arduino.

Ora il prossimo step è invece inviare un segnale ad arduino, ad esempio accendere il led 13 a richiesta.

Cerco un po' di discussioni...se hai consigli sono qui!

grazie ancora! :slight_smile: