Fnordlicht/Fernsteuern - RS232

From Lochraster

Jump to: navigation, search

Um die Farben des Fnordlichtes direkt über die serielle Schnittstelle zu setzten, muss man die Firmware (fnordlicht-ng-0.2) einwenig anpassen...


Contents

[edit] Anpassen der Firmware

die Datei fnordlicht.c muss geändert werden - und zwar kommt in folgende Routine

void check_serial_input(uint8_t data)

dieser Code rein (den bisherigen löschen)

   static uint8_t expectdata = 0;
   static uint8_t command = 0; //letzter Befehl   
   static uint8_t currentstate = 0;
   static uint8_t fade_speed = 0; //wenn größer 0 wird gefadet, anstatt die Farbe direkt zu setzten
	   
   currentstate = checkcommand(data);//Befehlszuordnung

   if(!expectdata){
	if (currentstate == 1) {//Sonderbefehle
   	    switch(data) {
	    case 'i': jump_to_bootloader(); break;
	    case 'p': jump_to_bootloader(); break;
	    }	
	} else if (currentstate > 1) {//0 wird ausgelassen

	    /*für Befehle die noch Werte brauchen*/
	    command = data;
	    UDR = command;
	    expectdata = 1;
	}	
   }
   else {
	if (checkcommand(command) == 2) {//Farbsetz-Befehle

	    static uint8_t color = 0;
	    switch(command) {
	    case 'r': color = 0; break;
	    case 'g': color = 1; break;
	    case 'b': color = 2; break;
	    }

	    if(fade_speed){
		/* wenn zu den übergebenen farbcode gefadet werden soll */
   	        global_pwm.channels[color].speed_h = HIGH(fade_speed);
   		global_pwm.channels[color].speed_l = LOW(fade_speed);
	    }else {
		/*wenn die übergebene Farbe sofort gesetzt werden soll */
   	        global_pwm.channels[color].brightness=data; 
	    }

   	    global_pwm.channels[color].target_brightness=data;
	    
	} else if (checkcommand(command) == 3) {//weitere Farbsetz-Befehle
	    switch(command) {
	    case 'f': fade_speed = data; break;
	    }
	}

	expectdata = 0;
	UDR = 's';
   } 

diese Zeilen benötigen noch die Funktion checkcommand(). Dafür müssen wir folgenden Code davor (am besten direkt vor der oben genannten Routine) einfügen

/*für das Einordnen der Befehle*/
uint8_t checkcommand(uint8_t data) {

   /*Sonderbefehle (erwarten keine weiteren Werte*/
   static const uint8_t extracommandlist[] = {'i','p',0};
   /*Farbsetzbefehle*/
   static const uint8_t colorcommandlist[] = {'r', 'g', 'b', 0};
   /*weitere Farbbefehle*/
   static const uint8_t otherextracommandlist[] = {'f', 0};    

   const uint8_t *b1 = extracommandlist;
   const uint8_t *b2 = colorcommandlist;
   const uint8_t *b3 = otherextracommandlist;    
   
   while(*b1){
	if(*b1 == data)
	    return 1;
	b1++;
   }
								 
   while(*b2){
	if(*b2 == data)
	    return 2;
	b2++;
   }

   while(*b3){
	if(*b3 == data)
	    return 3;
	b3++;
   }    
													      
  return 0;
}

Jetzt muss man nur noch die statischen Skripte in config.h deaktiviern:

#define STATIC_SCRIPTS 0

und das ganze auf das Fnordlicht bekommen...

[edit] Kompilieren und Flashen

zum löschen der alten Dateien

$ make clean

zum kompilieren und flashen

$ make install 

zum booten

$ echo X > /dev/ttyS0

jetzt kann man die Funktionen testen

[edit] Beschreibung der Steuerung

Unsere geänderte Firmware unterstützt nur wenige Befehle - die vorhandenen sind hier aber kurz aufgeführt.

allgemein kann man so:

$ echo BEFEHL > /dev/ttyS0

einen Befehl an das Fnordlicht senden (wenn es an /dev/ttyS0 angeschlossen ist)


dabei wird als BEFEHL folgendes interpretiert:

p oder i veranlassen einen Neustart

Das setzen der Farbe ist durch das senden eines Zeichens zur Wahl des Farbkanals (r,g bzw b) und ein darauf folgendes Byte zum setzten der Helligkeit möglich. So bewirkt z.B.

$ echo g² > /dev/ttyS0

das der grüne Farbkanal recht hell wird (² hat den Zeichencode 253)

Ein weiterer Befehl ist f und ein folgendes Byte zum setzten der Fadegeschwindigkeit aller Folgenden Farbänderungen. (Für das folgende Byte gillt: 0 setzt die Farbe sofort, 1 ist die langsamste und 255 die schnellste Fadestufe)


(den Funktionsumfang könnte man noch erweitern, da einige bisher unterstützte Befehle weggefallen sind)

[edit] vereinfachte Ansteuerung

Damit das Ansteuern einfacher wird brauchen wir ein Programm, dass uns die helligkeits Bytes generiert und ans Fnordlicht sendet. Dafür kann man den folgenden Code nutzen

/*
 * http://www.easysw.com/~mike/serial/serial.html
 */


#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

#include <time.h>

/*
 * 'open_port()' - Open serial port 1.
 *
 * Returns the file descriptor on success or -1 on error.
 */

int open_port(void)
{
    int fd; /* File descriptor for the port */
    
    
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)
    {
	  /*
	   * Could not open the port.
	   */
	  
	  perror("open_port: Unable to open /dev/ttyS0 - ");
    }
    else
	  fcntl(fd, F_SETFL, 0);
    
    return (fd);
}


int msleep(unsigned long milisec)
{
   struct timespec req={0};
   time_t sec=(int)(milisec/1000);
   milisec=milisec-(sec*1000);
   req.tv_sec=sec;
   req.tv_nsec=milisec*1000000L;
   while(nanosleep(&req,&req)==-1)
        continue;
   return 1;
}


int main(int argc, char** argv) {

    
int red = atoi(argv[1]);
int blue = atoi(argv[2]);
int green = atoi(argv[3]);

printf("%i %i %i\n",red,blue,green);

int fd = open_port();

struct termios options;

/*
 * Get the current options for the port...
 */

tcgetattr(fd, &options);

/*
 * Set the baud rates to 19200...
 */

cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);

/*
 * Enable the receiver and set local mode...
 */

options.c_cflag |= (CLOCAL | CREAD);

/*
 * Set the new options for the port...
 */

tcsetattr(fd, TCSANOW, &options);

options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8;    /* Select 8 data bits */

options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;

/*
 * Choosing Raw Input
 */

options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

int n;
unsigned int t=0;
char* a=(char*)&t;

// write(fd, "X", 1);

write(fd, "r", 1);
t = red;
a = (char*)&t;
write(fd, a, 1);

write(fd, "g", 1);
t = blue;	
a = (char*)&t;
write(fd, a, 1);

write(fd, "b", 1);
t = green;
a = (char*)&t;
write(fd, a, 1);

// write(fd, "X", 1);
//
// write(fd, "r", 1);
// write(fd, a, 1);
//
// write(fd, "g", 1);
// write(fd, a, 1);
//
// write(fd, "b", 1);
// write(fd, a, 1);
//
//
// unsigned int max = 100;
// unsigned int sleeptime = 10;
// char test = '0';;
//
// for(t=0;t<max;++t){
//      write(fd, "r", 1);     
//      a = (char*)&t;
//      test = a[0];
//      printf("%c\n",test);
//      write(fd, a, 1);
//      msleep(sleeptime);
//      
// }
//
// 
// for(t=0;t<max;++t){
//      write(fd, "g", 1);     
//      a = (char*)&t;
//      write(fd, a, 1);
//      msleep(sleeptime);
//      
// }
// 
// 
// for(t=0;t<max;++t){
//      write(fd, "b", 1);     
//      a = (char*)&t;
//      write(fd, a, 1);
//      msleep(sleeptime);
// }      
      
}

diesen muss man kompilieren

$ gcc QUELLCODE.c -o PROGRAMM

Jetzt kann man das neue Programm mit drei Parametern aufrufen, um eine Farbe zu setzen. So kann man, wenn das Programm "serial-control" heißt, es so aufrufen:

$ ./serial-control 120 30 60 

um rot auf 120 etc zu setzen