# Ringpuffer und Klassenarray



## hallohallo222 (22. Nov 2013)

Hallo,

also die Aufgabe ist es 3 verschiedene Werte von einer Hardware zu holen, diese dann alle 500ms von der HW in den Ringpuffer schreiben und halt auszulesen und Grafisch nach der Zeit darzustellen(y-Achse: Werte und x-Achse: Zeit). Also 3 Graphen sind es insgesamt.

Das ganze wurd jetzt mit einem Timer-Event realisiert, die werde wurden also einfach immer eingelesen und gezeichnet, wenn es einen Timer_interrupt gab, aber nun muss das ganze mit Ringpuffer realisiert werden(Graphen zeichen und Werte einlesen hat ja schon geklappt mit Timer).

Hier mein Ansatz:


```
class Write_Task implements Runnable {
		Thread thread;

		public Task1() {
			thread = new Thread(this);
		}

		  public void run() {
			int anz;
			Daten[] src;
			//hier irgendwie die Daten auslesen, aber wie ist die Frage
			
			System.out.println("Task 1 gestartet!");
			anz = rbf.write(src, 1);
			while (anz < 1) {
				anz += rbf.write(src, 1);
			}
			System.out.println("anz = " +anz);
			try {
				thread.sleep(500); // Erfassung alle 500 ms
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	

	class Read_Task implements Runnable {
		Thread thread;

		public Task2() {
			thread = new Thread(this);
		}

		public void run() {
			int anz;
			Daten[] dest = new Daten[10];

			System.out.println("Task 2 gestartet!");

			do {
				anz = rbf.read(dest, 1);
				
			} while (anz > 0);
		}
	}
}
```

Die Klasse "Daten" ist selbsterstellt und darin befinden sich die 3 get-Methoden, die 3 Werte von der Hardware holen. Naja eig. ist der Ringpuffer ja umsonst, da man nur Wert für wert rein schreibt und dann halt wert für wert liest.  Aber egal, die Aufgabenstellung will es halt so. 

Mir ist aber noch nicht so klar, was nun dieses Klassen-Array Daten bezwecken soll. In einem normalen Integer Array stehen doch Integer-Werte darin, aber was hilfst das Array Daten hier weiter? Was steht da in einem Feld? Objekte bzw. Instanzen von der Klasse Daten?

Also hätte wer einen Tipp, wie ich das so machen könnte? Also alle 3 Werte irgendwie in so ein "klassen-array" speichern und dann in den Ringpuffer schreiben, um in dann leicht wieder lesen zu können, sodass kein durcheinander der Werte kommt.

Danke!

mfg


----------



## hallohallo222 (23. Nov 2013)

Das gibt es doch nicht. Kann mir jemand helfen bitte ?


----------



## hallohallo222 (23. Nov 2013)

Keine hat eine Ahnung vom Ringpuffer in Java bzw. keiner kann mein Problem lösen?

Sagt es doch, wenn ihr was nciht versgeht, an meinem Problem.


----------



## hallohallo222 (23. Nov 2013)

Sorry, Leute, aber ich verstehs echt nicht. Werde ich ignoriert, weil jeder denkt das ist eine Hausaufgabe und ich soll sie selber ALLEINE machen?

Ich will doch nur Tipps abholen. Ich kann mir das auch nicht mit Hilfe des Internets erarbeiten, da ich nicht weiß wie ich rangehen soll an die Sache.


----------



## rme (23. Nov 2013)

Hm. Also ich habe diesen Beitrag bisher nicht beantwortet, weil ich den Code nicht nachvollziehen kann. Da wird zum Beispiel innerhalb einer Runnable ein Thread erzeugt, aber nicht gestartet. Auf welche Weise könnte dieser Thread denn jemals gestartet werden? Wenn du run() auf dem Runnable aufrufst, passiert das ja nicht in einem eigenen Thread. Dazu müsstest du start() auf dem Thread aufrufen, aber das kann von außerhalb ja gar nicht passieren, weil es nach außen nur eine Runnable ist.

Weiterhin habe ich nicht verstanden, was ein Klassen-Array sein soll. Ein Array vom Typ Class? Oder vielleicht doch ein Objekt-Array? src und dest sind bei dir Objekt-Arrays, aber ich sehe da keinerlei Ringpuffer-Funktionalität.


----------



## hallohallo222 (23. Nov 2013)

Um das Thread starten geht es doch gar nicht, das wird natürlcih außerhalb irgendwo gemacht, ich hab doch nur mein Problem beschrieben.

Zum Klassenarray bzw. Objektarray(ich hab nciht gewusst das das so heißt):
Alle 500ms wird doch in den Ringpuffer geschrieben bzw. so muss ich das machen. Aber ich hab doch 3 Werte. Wie soll ich das realisieren? Kann in src[0] alle 3 Werte(wert1,wert2,wert3) stehen? Nein oder? Ich verstehe noch nicht so ganz was dieses Klassenarray bezwecken soll.

Ich muss doch auch die Werte dauernd auslesen. Kann ich nicht die 3 verschiedenen Werte in ein Gesamtpaket(also z.b. auf src[0]) verfrachten, dies dann in den Buffer schreiben und anschließend das Paket lesen und 3 Graphen daraus machen? 

rbf ist ein Objekt von der Klasse Ringpuffer, das auch irgendwo gemacht wird. 

Da write und read vom ringpuffer.

```
public class Ringpuffer {
    private Datenbuf[];
    private int bufsize;
    private int next_read;
    private int cnt;
   
    public Ringpuffer (int size) {
        bufsize = size;
        buf = new Daten[bufsize];
        next_read = 0;
        cnt = 0;
    }
   
    public synchronized int write (Daten[] src, int num) {
        int geschrieben = 0;
       
        while((geschrieben < num) && (cnt < bufsize)) {
            buf[(next_read+cnt)%bufsize] = src[geschrieben];
            ++geschrieben;
            ++cnt;
        }  
       
        return geschrieben;
    }
   
    public synchronized int read (Daten[] dest, int num) {
        int gelesen = 0;
       
        while((gelesen < num) && (cnt > 0)) {
            dest[gelesen] = buf[next_read];
            ++gelesen;
            --cnt;
            next_read = (next_read+1)%bufsize;
        }
       
        return gelesen;
    }
   
}
```


----------



## rme (23. Nov 2013)

(Der Thread kann in dem Beispiel nicht von außen gestartet werden - deshalb war ich stutzig und hab nicht weiter gelesen. Aber du wirst wissen, was du tust, ich ignoriere das dann mal)

Ah. Also in deinen Arrays können 10 Werte vom Typ "Data" gespeichert werden. Wenn die 3 Werte irgendwie zusammenhängen, sind sie ja in den Instanzvariablen dieser Klasse gespeichert, oder? Dann können in jedem Element des Arrays indirekt 3 Werte gespeichert werden, insgesamt also 30. Falls da aber einfach nur get-Methoden sind, die int-Werte oder so zurückliefern, müsste dein Ringpuffer eigentlich auch vom Typ int sein.. interessant wäre es also, welche Methoden und Instanzvariablen die Daten-Klasse beinhaltet.


----------



## hallohallo222 (23. Nov 2013)

Naja, ich weiß ja gar net ob das so geht überhaupt. Also ist das das Ziel eines Objektarrays? Ich stehe da vollkommen an, wie ich das problem lösen sollte.


----------



## rme (23. Nov 2013)

Dein Ringpuffer beinhaltet bereits ein Array, in dem seine Daten gespeichert sind. Die read- und write-Methode erwarten auch jeweils ein Array als Parameter, weil sie den Puffer mit mehreren Elementen gleichzeitig befüllen wollen. Wenn du pro Schritt nur ein Element liest, kannst du einfach ein ein-elementiges Array erzeugen:


```
rbf.write(new Data[] {data}, 1);
```


----------



## hallohallo222 (23. Nov 2013)

Danke dir.

Aber ich habe doch 3 verschiedene Werte, die ich ja gleichzeitig übertragen will:

Temperatur, Sinus und Poti-Wert.


----------



## rme (23. Nov 2013)

Deshalb hatte ich vorhin gefragt, ob die Daten-Klasse diese Werte nur liefen kann, oder ob sie auch als Instanzvariablen darin gespeichert sind. Wenn letzteres der Fall ist, funktioniert das obige Beispiel schon, weil ja in Daten alle 3 Werte enthalten sind.. Wenn die Daten von der Klasse wiederum nur ausgelesen werden können, kann der Ringpuffer nicht vom Typ Daten sein.


----------



## hallohallo222 (23. Nov 2013)

Naja man muss schon getTemperatur, getPoti und getSinus machen, um die WErte zu bekommen.

Also wie meinst du das genau?


----------



## rme (23. Nov 2013)

Löst getTemperatur das Auslesen auf der Hardware aus oder wurde das schon vorher gemacht, sodass getTemperatur nur sowas wie "return temperatur;" enthält?


----------



## hallohallo222 (23. Nov 2013)

Liest von der Hardware.

Also z.b.:


```
public float get_TEMP() {
		try {
			fTEMP = my_prot.prot_get_temp(); // holt von Hardware den temp-wert
		} catch (ProtException e) {
			e.printStackTrace();
		}
		return(fTEMP);
	}
```


----------



## rme (23. Nov 2013)

Ist es vorgeschrieben, dass der Ringpuffer den Typ "Daten" hat? In diesem Fall müsstest du deine "Daten"-Klasse so ändern, dass die Werte durch eine andere Methode in Instanzvariablen gespeichert werden und get_TEMP diese dann einfach zurückgibt. Dann könntest du nämlich einen ganzen Datensatz im Ringpuffer ablegen, mit read auslesen und dann get_TEMP auf so einem Datensatz aufrufen, um an die Temperatur zu kommen.

Der andere Weg wäre es, im Ringpuffer floats statt "Daten"-Objekte zu speichern. Dann würde du so ein Tripel so speichern:


```
rbf.write(new float[] {daten.get_TEMP(), daten.get_SIN(), daten.get_whatever()}, 3);
```

Aber bei näherer Überlegung denke ich, dass der erste Weg der einzig sinnvolle ist - in einem Ringpuffer hast du nämlich keine Chance rauszufinden, ob ein Wert nun eine Temperatur, ein Sinus oder sonstwas ist.

Ergo: Schreib deine Daten-Klasse um, also füg eine auslesen()-Methode hinzu, die alle Werte ausliest, speichert und dann in den Ringpuffer wandern kan.


----------



## hallohallo222 (23. Nov 2013)

Danke. Hm ich weiß so ganz noch nicht was du meinst leider. 

Hier mal die Vollständige Klasse Daten:

```
public class Daten{
	private float fAN1 = 0;
	private float fAN2 = 0;
	private float fTEMP = 0;
	private Prot my_prot = new Prot(); // neue Klasse anlegen zum ringebuffer realisieren diese ist nur für die communication zuständig
	
	public Daten(String COM_PORT) {
		my_prot.prot_init(COM_PORT);
	}
	
	public float get_AN1() {
		// <--- hier lokal die variabeln von oben anlegen
		try {
		fAN1 = my_prot.prot_get_poti();
		} catch (ProtException e) {
			e.printStackTrace();
		}
		return(fAN1);
	}
	
	public float get_AN2() {
		try {
			fAN2 = my_prot.prot_get_AN2();
		} catch (ProtException e) {
			e.printStackTrace();
		}
		return(fAN2);
	}
	
	public float get_TEMP() {
		try {
			fTEMP = my_prot.prot_get_temp();
		} catch (ProtException e) {
			e.printStackTrace();
		}
		return(fTEMP);
	}
	
	public void close_conn() {
		my_prot.prot_close();
	}
}
```

Hm vllt helfen dir auch die Comments hier als Hinweis weiter, die wurden mir mitgegeben. Kann ich da nicht auch das iwie im Konstruktor von der Klasse Daten lösen?


----------



## rme (23. Nov 2013)

Puh.. was genau soll eigentlich im Ringpuffer gespeichert werden? Mir ist die Aufgabe irgendwie immernoch unklar.. Denn die Daten-Klassie kommuniziert ja mit der Hardware, eigentlich geschieht sowas über einen Ringpuffer - aber du verwendest den Ringpuffer ja an einer ganz anderen Stelle und speicherst die Kommunikationsobjekte. Für mich ergibt der Zusammenhang irgendwie wenig Sinn :/


----------



## hallohallo222 (23. Nov 2013)

Hm naja, vllt hab ich es auch falsch gemacht.

Also meinst du, dass die Klasse Daten unnötig ist?


----------



## rme (23. Nov 2013)

Nein. Nur würde ich das Auslesen von der Hardware in eine Methode auslagern, die die drei Werte in die Variablen liest und in den get-Methoden dann nur diese Werte mit return zurückgeben.

Dann ergibt es nämlich plötzlich alles Sinn mit dem Ringpuffer - der würde dann Tripel aus den gelesenen Werten in Form der "Daten"-Objekte enthalten.


----------



## hallohallo222 (23. Nov 2013)

Also soll ihc z.b. einfach eine neue Methode in der Klasse Daten machen und dann hier alle gets aufrufen?

Und die Werte dann wo speichern? In Daten klasse?


----------



## rme (23. Nov 2013)

In der neuen Methode nicht die get-Methoden aufrufen, sondern diese drei Zeilen:


```
fAN1 = my_prot.prot_get_poti();
 fAN2 = my_prot.prot_get_AN2();
 fTEMP = my_prot.prot_get_temp();
```

Die jetzigen get-Methoden machen dann nur das Return. Auf diese Weise sind die Werte doch in je einem "Daten"-Objekt gespeichert. Du kannst also deine "Daten"-Objekte in den Ringpuffer legen, von da wieder auslesen und dann mit den get-Methoden die gespeicherten Werte auslesen.

Das setzt voraus, dass die Aufgabe lautete, die gelesenen Werte in einem Ringpuffer zu speichern - und nicht das Lesen auf Protokoll-Ebene zu puffern.


----------



## hallohallo222 (23. Nov 2013)

Danke!

Meinst du so?(seihe code) Aber ich verstehe nicht, was das nun für einen Unterschied macht.

Soll ich nun einfach die getMethoden in meinen Write_Thread aufrufen, oder wie kann man an eine STelle von einen Array 3 Werten haben, dass begreife ich leider noch nicht.



```
public class Daten {
	private float fAN1 = 0;
	private float fAN2 = 0;
	private float fTEMP = 0;
	private Prot my_prot = new Prot(); // neue Klasse anlegen zum ringebuffer realisieren diese ist nur für die communication zuständig
	
	public Daten(String COM_PORT) {
		my_prot.prot_init(COM_PORT);
	}
	
	public void get_All() {
	    try {
			fAN1 = my_prot.prot_get_poti();
			fAN2 = my_prot.prot_get_AN2();
		     fTEMP = my_prot.prot_get_temp();
		} catch(ProtException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	     
	}
	
	public float get_AN1() {
		// <--- hier lokal die variabeln von oben anlegen

		return(fAN1);
	}
	
	public float get_AN2() {
	
		return(fAN2);
	}
	
	public float get_TEMP() {
		
		return(fTEMP);
	}
	

	public void close_conn() {
		my_prot.prot_close();
	}
}
```


----------



## rme (23. Nov 2013)

Ja, so meinte ich das. Der Unterschied ist: Du kannst nun get_All aufrufen und das Objekt danach in den Ringpuffer schreiben. Irgendwann liest du sie dort wieder aus. Das Array besteht ja genau aus Objekten von diesem Typ - du kannst also nach dem Auslesen von einem Wert aus dem Array 3 Werte aus diesem Wert bekommen. Nämlich so:


```
Daten[] readData = new Daten[1];
rbf.read(readData, 1); // ein Daten-Element lesen
float temperatur = readData[0].get_TEMP(); // temperatur aus dem Element holen
float an1 = readData[0].get_AN1();
float an2 = readData[0].get_AN2();
```

So hast du aus einem Array-Element 3 Werte gelesen. Vorher war es so, dass die get_TEMP-Methode die Daten von der Hardware gelesen hätte - aber das soll natürlich irgendwann vorher passiert sein.

Es sei denn, ich hab die Aufgabe falsch verstanden und das eigentliche Lesen der Hardware sollte schon gepuffert werden..


----------



## hallohallo222 (23. Nov 2013)

Danke, siehe comments.


```
class Write_Task implements Runnable {
        Thread thread;
 
        public Task1() {
            thread = new Thread(this);
        }
 
          public void run() {
            int anz;
            Daten data = new Daten();
            Daten[] src = new Daten[10];

            //Wie soll ich hier da get_all aufrufen?
            data.get_All(); // so?
             // und wo soll ich dann die ganzen werte holen?

           
            System.out.println("Task 1 gestartet!");
            anz = rbf.write(src, 1);
            while (anz < 1) {
                anz += rbf.write(src, 1);
            }
            System.out.println("anz = " +anz);
            try {
                thread.sleep(500); // Erfassung alle 500 ms
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
```

Anders Problem, wenn ich aber hier die ganze zeit new mache, da es ja ein Thread ist, der das immer aufruft, wird ja immer neue verbindung gemacht, also der konstruktor von Daten aufgerufen oder?


----------



## rme (23. Nov 2013)

Zum Auslesen: src brauchst du nicht mehr. Du rufst data.get_all() auf, damit sind die 3 Werte gefüllt und können in einen (!) Slot des Ringpuffers geschrieben werden:


```
rbf.write(new Daten[] {data}, 1);
```

Zum Thread: Richtig, der Konstruktor wird immer aufgerufen und dadurch eine neue Verbindung erzeugt. Wenn das nicht so sein soll, gehört die Proto-Instanz nach außen und wird der Daten-Klasse im Konstruktor übergeben. Also du erzeugst einmal Proto, übergibst das bei jedem new an Daten und das kann dann die hergestellt Verbindung verwenden.


----------



## hallohallo222 (23. Nov 2013)

aso hmm.

Aber was macht folgendes:

rbf.write(new Daten[] {data}, 1);

Dieses new Daten[] {data}?


----------



## rme (23. Nov 2013)

Das legt ein Array der Größe 1 an, in dem das data-Objekt enthalten ist.


----------



## hallohallo222 (23. Nov 2013)

Aha! Also erstelle ihc mal ein Objekt von Daten, dass einmal die Werte reinholte und dann mache ich ein neues in dem ich einfach new Daten[] machen. Und dann schreibt es einfach in den puffer das Objekt rein(aber nicht die Werte, richtig?) und man kann dann von puffer lesen.

Aber naja für was das {data}? Geht ja ohne auch oder?


----------



## rme (23. Nov 2013)

Die Daten schreibt du indirekt doch rein, weil sie in data enthalten sind (die Instanzvariablen, die get_All einliest). 

Wenn die {} weglässt, ist es kein Array mehr - und deine write-Methode erwartet ein Array, weil mehrere Werte auf einmal in den Puffer geschrieben werden können.

Ich bin mir weitehrin völlig unsicher, ob ich deine Aufgabe und die Anforderungen richtig verstanden habe.. aber du hast es ja so gewollt, dass dir jemand antwortet


----------



## hallohallo222 (24. Nov 2013)

Naja, das klingt doch eh plausibel, was du mir da versuchst du erklären bzw. dein Lösungsweg^^.

Aber ich dachte es ist ein Arry wenn man ECKIGE KLAMMERN [] macht. Ich hab noch nie was von den GESCHWUNGENEN KLAMMERN {} gehört .


----------



## rme (24. Nov 2013)

Eckige Klammern beim Zugreifen, geschweifte beim Anlegen zum Angeben der Elemente, die schon beim Anlegen drin sein sollen


----------

