AdSense

Dienstag, 28. Mai 2013

PHP - Passwort als Hash und nicht als Klartext speichern

(English version) Momentan schreibe ich an einem textbasierten Online-Spiel. Da man sich da ja anmelden kann, muss ich die Passwörter der User speichern. Prinzipiell ist das ja ganz einfach, das Password wird auf dem Server einfach in eine Datei geschrieben, auf die man vom Internet aus keinen Zugriff hat. Das Problem ist jetzt: Was wäre, wenn ein User sein Master-Passwort, welches er auch für Bankkonten und ähnliches benutzt, angibt? Ich könnte mir dann ja das Passwort anschauen und viele Dummheiten damit machen. Daher sollte das Passwort nicht als Klartext gespeichert werden.

Die Lösung für dieses Problem ist die Verwendung von einer Hash-Funktion (http://de.wikipedia.org/wiki/Hash-Funktion). In php funktioniert das folgendermaßen:

$passwort = hash('ripemd160', $passwort);

Ich bekomme von "hash" eine Zahlen- und Buchstabenfolge, die (mit sehr hoher Wahrscheinlichkeit) eindeutig ist. Im php Code wandle ich alle Eingaben des Passwortes sofort um, sodass immer nur mit dem hash-Wert gearbeitet wird (Vergleiche, Abspeichern). Aus diesem Wert kann man jedoch nicht ohne weiteres das Passwort herausfinden, daher nützt es auch überhaupt nichts, wenn jemand den Wert kennt, da dieser ja bei der Eingabe erneut umgewandelt werden würde, was einen komplett anderen Wert zurückgibt. Damit ist es also unmöglich, das Passwort herauszufinden oder zu knacken, da das Passwort nirgends gespeichert wird.

Sonntag, 26. Mai 2013

ATmega - Hardware-SPI

(English version) SPI-Kommunikation kann ziemlich praktisch sein (z.B. um einen Raspberry PI mit ATMegas um weitere Digitalkanäle zu erweitern). Für das SPI-Interface am ATMega8 habe ich jedoch kaum Informationen gefunden, daher hier der Code, welchen ich nach langem Zusammensuchen hatte. Die einzelnen Funktionen sollten selbsterklärend sein:

void SPI_SlaveInit(void)
{
  DDRB |= (1<<PORTB4);//Set MISO to output
  SPCR = (1<<SPE);
}

char SPI_SlaveReceive(void)
{
  char data;
  while(!(SPSR & (1<<SPIF)))
  {}
  data = SPDR;
  SPDR = 0;
  return data;
}

void SPI_SlaveSend(char data)
{
  SPDR = data;
  while(!(SPSR & (1<<SPIF)))
  {}
  SPDR = 0;
}

Samstag, 25. Mai 2013

ATmega - ESC ansteuern

(English version) Ich habe heut meinen Brushless-Motor aus China bekommen, das Steuergerät (ESC) kam schon eine Woche früher an. Nun wollte ich natürlich den Motor bewegen. Ich habe vieles im Internet zum Thema "ESC, PWM" gelesen aber eine genaue Anleitung wie es wirklich funktioniert gab es nicht.

Ein ESC ist folgendermaßen aufgebaut: 3 Kabel für den Motor (welches Kabel an welches am Motor kommt ist prinzipiell egal, falls der Motor sich falschrum dreht müssen einfach 2 vertauscht werden), 2 Kabel für den Akku (+, -) und 3 Kabel für das Steuern der Motor-Geschwindigkeit per PWM.

PWM funktioniert prinzipiell so, dass der Ausgang für eine gewisse Zeit des Zyklus an ist und dann aus geht. Beim ATMega zählt ein Counter bis 255 hoch. Setzt man nun den PWM-Ausgang auf einen Wert (z.B. 150), so ist der Ausgang während dem Zählen von 1 bis 150 high und dann von 150 bis 255 low. Wie das mit dem ATMega funktioniert sieht man unten im fertigen Programm.

Die 3 ESC-Kabel sind bei mir schwarz (geht an Masse), rot (wird nicht verbunden) und weiß (hier kommt das PWM-Signal hin). Ich steuere den ESC mit einem ATMega an, der hat ja Hardware-PWM. Um den Motor benutzen zu können muss aber erstmal eine Sequenz durchgefahren werden:
1) Das "Maximale-Leistung"-PWM-Signal, bis der Motor ein paar mal piepst (bei mir ist das 250)
2) Das "Keine-Leistung"-PWM-Signal, der Motor piepst dann andere Töne (bei mir 150).
Nun kann man ein PWM-Signal (bei mir von 150 bis 250) anlegen und den Motor dementsprechend steuern.

Hier mein Code um den ESC zu kalibrieren und dann den Motor auf voller Leistung anzuschalten:

#include <avr/io.h>
#define F_CPU 16000000
#include <util/delay.h>

int main( void )
{
  DDRB=0xFF; //Alle PORTB-Anschlüsse als Ausgang festlegen
  OCR2=250; //250 von 255, also fast die ganze Zeit high
  TCCR2=0x6D; //Frequenz auf etwas mehr als 50 Hz einstellen

  _delay_ms(10000);//Warten bis der Motor piepst
              //(10 Sekunden sind schon zu viel, aber zu viel schadet ja nicht)
  OCR2 = 150;((//150 von 255, also das Minimale-Leistung-Signal für den ESC
  _delay_ms(10000);
//Warten bis der Motor fertig ist

  //Jetzt ist der ESC kalibriert und kann verwendet werden.
  //OCR2 = 150: Minimale Leistung
  //OCR2 = 250: Maximale Leistung

  OCR2 = 200;//Auf halbe Leistung schalten
  while (1)
  {}
}

Dienstag, 21. Mai 2013

Fettkraut und Sonnentau vermehren

(English version) Hier sieht man meine 5 Fettkräuter:
Links oben ist die Mutterpflanze, ganz rechts eine weitere Hälfte davon (sie hat sich irgendwann geteilt). Die drei großen Pflanzen habe ich über Blattstecklinge geschaffen. Das Grundprinzip ist einfach: Ein Blatt möglichst nahe der Wurzel abreißen, auf feuchte Erde legen und warten.

Zwei wichtige Punkte werden jedoch fast nie erwähnt:
a) Die Pflanze braucht Luftfeuchtigkeit. Ich habe daher über den kompletten Topf eine Plastiktüte gezogen.
b) Licht. Seitdem ich die Pflanzen mit einer Energiesparlampe beleuchte (6400 K, 5 W), wachsen sie deutlich besser und schneller. Ich bin mir aber nicht ganz sicher, ob das Licht direkt der ausschlaggebende Punkt ist oder eher die Wärme (und damit unter der Plastiktüte vor allem die Luftfeuchtigkeit).

In den anderen Töpfen wächst bei mir Sonnentau (ganz frische kleine Pflanzen). Im rechten kleinen Topf war zuerst ein Pflänzchen, welches etwa 1 mm groß war (also kaum erkennbar), inzwischen ist das auf mindestens 5 mm angewachsen und scheint auch noch munter weiter zu wachsen. Entgegen allen Aussagen gieße ich diese Pflanzen mit normalen Leitungswasser (was bei uns ziemlich Kalkhaltig ist). Dem Fettkraut macht es nichts aus und den kleinen Sonnentau-Pflänzchen auch nicht.

Die Vermehrung von Sonnentau funktioniert genau wie bei dem Fettkraut, man muss die gleichen Dinge beachten. Die Mutterpflanze von meinem Sonnentau war eine zu 90% braune Pflanze (es gab in dem Laden keine schöneren Pflanzen). Einzelne Blätter wurden dann unter hoher Luftfeuchtigkeit auf feuchte Erde gelegt und an einigen Stellen haben sich winzige Pflänzchen gebildet, von denen drei überlebt haben (natürliche bzw. forcierte Selektion). Ich versuche, diese Pflanzen auf "normales" Wasser einzustimmen, vielleicht klappt das ja, da werde ich in einiger Zeit Ergebnisse posten können.

Montag, 20. Mai 2013

ATmega - Temperaturmessung mit dem DS18S20

(English version) Um die Temperatur in meinem Zimmer zu messen benutze ich einen DS18S20, dies ist ein 3-Pin-Temperatursensor (sieht aus wie ein Transistor), welcher digital von einem ATmega8 ausgelesen wird. Die Genauigkeit liegt laut Herstellerangabe bei ± 0,5 °C. Der Sensor hat folgende Anschlüsse: Vcc (bei mir +5V), Gnd und den Daten-Pin. Genaue Infos zu dem Übertragungsprotokoll gibt es im Datenblatt, hier ist mal der Code, wie ich die Temperatur via ATmega auslese. Zu beachten ist: PORTD0 ist Ausgang, PORTD2 Eingang und beide Pins sind mit dem Daten-Pin des Sensors verbunden:

void on()
{
  PORTD |= (1 << PORTD0);
}

void off()
{
  PORTD &= ~ (1 << PORTD0);
}

void write(int hilow)
{
  if (hilow == 0)
  {
   off();
   _delay_us(80);
   on();
   _delay_us(20);
  }
  else
  {
   off();
   _delay_us(5);
   on();
   _delay_us(95);
  }
}

void read()
{
  off();
  _delay_us(2);
  on();
  _delay_us(98);
}

double read0()
{
  double retVal = 0;
  off();
  _delay_us(2);
  on();
  _delay_us(1);
  if (PIND & (1 << PIND2)) //HIGH
  {
    retVal = 1;
  }
  else
  {
    retVal = 0;
  }
  _delay_us(97);
  return retVal;
}


double measureTemp()
{
  double temp = 0;
  double fac = 0.5;
  double neg = 0;
  double value = 0;

  off();
  _delay_us(500);
  on();
  _delay_us(1000);

  write(0);
  write(0);
  write(1);
  write(1);
  write(0);
  write(0);
  write(1);
  write(1);

  _delay_us(100);
  //Start temperature conversion
  write(0);
  write(0);
  write(1);
  write(0);
  write(0);
  write(0);
  write(1);
  write(0);

  _delay_us(1000);

  off();
  _delay_us(500);
  on();
  _delay_us(1000);

  write(0);
  write(0);
  write(1);
  write(1);
  write(0);
  write(0);
  write(1);
  write(1);

  _delay_us(100);
  //read Temperature
  write(0);
  write(1);
  write(1);
  write(1);
  write(1);
  write(1);
  write(0);
  write(1);

  value = read0();

  temp += fac * value; fac = fac*2; 
  bits[0] = value;

  value = read0();
  temp += fac * value; fac = fac*2;
  bits[1] = value;

  value = read0();
  temp += fac * value; fac = fac*2;
  bits[2] = value;

  value = read0();
  temp += fac * value; fac = fac*2;
  bits[3] = value;

  value = read0();
  temp += fac * value; fac = fac*2;
  bits[4] = value;

  value = read0();
  temp += fac * value; fac = fac*2; 
  bits[5] = value;

  value = read0();
  temp += fac * value; fac = fac*2;
  bits[6] = value;

  value = read0(); 
  temp += fac * value;  bits[7] = value;
  //das letzte Bit beachte ich nicht, wenn man später count_remain mit einbezieht, ist dies nicht mehr nötig.

  neg = read0();
  read();
  read(); 
  read();
  read();
  read(); 
  read();
  read();

  //TH 
  read(); 
  read(); 
  read(); 
  read();
  read(); 
  read();
  read();
  read();

  //TL 
  read(); 
  read();
  read();
  read(); 
  read();
  read(); 
  read(); 
  read();

  //Reserved 
  read(); 
  read(); 
  read(); 
  read(); 
  read(); 
  read(); 
  read(); 
  read();

  //Reserved
  read();
  read(); 
  read(); 
  read(); 
  read(); 
  read(); 
  read(); 
  read();

  //COUNT REMAIN 
  count_remain[0] = read0(); 
  count_remain[1] = read0();
  count_remain[2] = read0();
  count_remain[3] = read0();
  count_remain[4] = read0(); 
  count_remain[5] = read0(); 
  count_remain[6] = read0(); 
  count_remain[7] = read0();

  //COUNT PER °C 
  count_per_c[0] = read0(); 
  count_per_c[1] = read0();
  count_per_c[2] = read0(); 
  count_per_c[3] = read0(); 
  count_per_c[4] = read0(); 
  count_per_c[5] = read0(); 
  count_per_c[6] = read0(); 
  count_per_c[7] = read0(); 

  //CRC 
  read(); 
  read();
  read();
  read();
  read(); 
  read(); 
  read(); 
  read();

  //Man kann die Präzision erhöhen, indem man noch count_remain mit einbezieht.
  //Dies habe ich dann erst an einer späteren Stelle im Programm gelöst. 

  return temp;

}


C# Windows Forms - Image drehen

(English version) Für Panzerkampf ist es nötig, ein Bild zu drehen (z.B. für den Flammpanzer). Die Lösung, die ich benutze ist folgende:

private Image rotateImage(Image b, double angle)
{
  //create a new empty bitmap to hold rotated image
  Bitmap returnBitmap = new Bitmap(2*b.Width, 2*b.Height);
  //make a graphics object from the empty bitmap
  Graphics g = Graphics.FromImage(returnBitmap);
  //move rotation point to center of image
  g.TranslateTransform(center_x, center_y);
  //rotate
  g.RotateTransform(-(float)(angle*180.0/Math.PI));
  //move image back
  g.TranslateTransform(-center_x, -center_y);
  //draw passed in image onto graphics object
  g.DrawImage(b, new Point(0, 0));
  return returnBitmap;
}


Zu beachten ist, dass ich das Bild vergrößere (Faktor 2), da sonst das gedrehte Bild an manchen Kanten abgeschnitten sein kann. Zeichnet man dann das neue Bild und will die Mitte an den selben Punkt wie bei dem ungedrehten Bild setzen, so muss man natürlich den doppelten Offset benutzen.

Panzerkampf

(English version) Vor einige Jahren hatte ich mal unter Linux ein Spiel programmiert: Panzerkampf. Die Grundlegende Idee war, dass man an einem Computer mit Pfeiltasten bzw. WASD einen Panzer durch die Gegend fährt und versucht, den anderen Spieler auszuschalten. Leider war das Projekt ziemlich limitiert, eine Tastatur kann nicht beliebig viele Tasten abfragen und wenn nun zwei Spieler an einer Tastatur sitzen und jeweils mehrere Tasten drücken, kann es sein, dass der eine Spieler nicht mehr schießen kann.

Vor etwa zwei Wochen habe ich mich dann nochmal an das Spiel gemacht. Programmiert habe ich in C#, das Spiel ist nun auch Netzwerk-fähig (dafür muss ich aber den Server hier bei mir am PC gestartet haben). Die Netzwerk-Kommunikation funktioniert mit Sockets, hier ein kleines Codebeispiel dazu:

Client:

System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
clientSocket.Connect("mein.server.de", port);
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes("message to server");
//Nachricht an Server senden
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
byte[] inStream = new byte[70000];
//inStream anpassen (größe an clientSocket.ReceiveBufferSize anpassen)
Array.Resize(ref inStream, clientSocket.ReceiveBufferSize);
//Nachricht vom Server empfangen
serverStream.Read(inStream, 0, clientSocket.ReceiveBufferSize);
string dataFromServer = System.Text.Encoding.ASCII.GetString(inStream);
clientSocket.Close();


Server:

TcpListener serverSocket = new TcpListener(port);
TcpClient clientSocket = default(TcpClient);
serverSocket.Start();
clientSocket = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
byte[] bytesFrom = new byte[10025];
Array.Resize(ref bytesFrom, clientSocket.ReceiveBufferSize);
networkStream.Read(bytesFrom, 0, clientSocket.ReceiveBufferSize);
string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
Byte[] sendBytes = Encoding.ASCII.GetBytes("message to Client");
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
clientSocket.Close();


Für die Sounds habe ich Sounds von freesound.org benutzt, welche alle der Creative Commons 0 Lizenz unterliegen, ich also die Autoren nicht explizit erwähnen muss, ich darf lediglich nicht sagen, dass die Sounds von mir wären.

Die Grafiken male ich alle selber (C#, Windows Forms).

Den Download zu Panzerkampf gibts es hier: http://physudo.bplaced.net/Panzerkampf/publish.htm
Und den Server hier: http://physudo.bplaced.net/PanzerkampfServer/publish.htm

Falls es jemand ausprobiert würde ich mich freuen, wenn ich ein kleines Feedback (hier als Kommentar) bekommen könnte.

LED-Cube

(English version) Ich habe gestern und heute (mit Hilfe meiner Freundin) einen LED-Cube gebaut.

Größe: 4x4x4, bestehend aus grünen LEDs.
Angesteuert wird der Cube mit einem Atmega16A, dieser hat genug Output-Kanäle. PORTA und PORTC werden für die Spalten benutzt und PORTD3...6 für die Ebenen.

Hier kann man den Atmega sehen. Links sind 4 NPN-Transistoren, die genug Strom vertragen um eine komplette Ebene anzusteuern (16 LEDs, 20 mA, das macht ja schonmal 320 mA, was nicht gerade jeder Transistor verträgt). Die grundlegende Schaltungsidee sieht folgendermaßen aus: Alle LEDs übereinander sind an den Anoden (+) miteinander verbunden und gehen an einen der 16 Output-Kanäle des Atmegas (PORTA + PORTC). Die Kathoden (-) sind innerhalb einer Ebene miteinander verbunden und sind dann an den Kollektor eines Transistors geschaltet. Die Basis des Transistors hängt dann mit einem Widerstand an einem der PORTD-Ausgänge. Das Programmierkonzept ist auch relativ simpel: Jede Ebene hat eine Variable, die den Zustand jeder LED speichert (also von 0 bis FFFF). Die Ebenen werden nacheinander für jeweils 100 µs angeleuchtet, damit hat man eine Wiederholfrequenz von 2,5 kHz, das ist deutlich über dem, was ein menschliches Auge als Flackern erkennen kann.

Die LEDs haben oben alle einen weißen Klecks mit Deckweiß drauf, da sonst eine LED immer die darüberliegende von unten "anleuchtet" und es den Anschein macht, als würde die obere auch halb leuchten.

Der nächste Schritt ist die Einbindung von SPI, sodass ich von meinem Raspberry PI den Würfel direkt ansteuern kann.