Open Sound Control Protokoll (OSC) brauche php-Hilfe

Hallo in die Softwerker-Gemeinde,
ich bin gerade beim testen eines neuen Projektes, welches die Steuerung von verschiedenen RGB-LEDs per IPS über einen Arduino-Controller und OSC bei mir übernehmen soll.
Dazu habe ich die „Steuerkette“ wie folgt aufgebaut:

iPad mit TouchOSC, gekoppelt per WLAN mit dem Heimnetzwerk, Arduino mit Ethernet-Add-On ebenfalls am Heimnetzwerk, darauf die Software als OSC-Client, der 3 PWM-Ausgänge des Arduino steuert.
Dahintergeschaltet ein RGB-Amplifier und 5m RGB-LED Strip.

Das Ganze funktioniert auch ganz toll, d.h. ich kann per Schieberegler auf dem iPad die einzelnen Farbkanäle der LED-Strips steuern.
Nun soll hierzwischen IPS eingreifen können, um durch verschiedene scripts z.B. verschiedene Farben auswählen zu können.
Dazu müsste ich per UDP an den Arduino Daten des OSC-Protokolls senden.
Hat sich jemand damit schonmal beschäftigt und kann mir da bei php unter die Arme greifen?
Ich habe die Byte-Folgen im Netzwerk mitgeloggt und komme auf einen „festen“ Anteil, der den Kanal und die Farbe repräsentiert, und auf einen variablen Anteil, der einen 4byte Hex Wert darstellt.
Den PWM-Farbwert (float 0 bis 255) muss man irgendwie in diesen 4-byte-Hex-Wert wandeln. Ich habe das mit der „pack“-Funktion probiert, aber irgendwie gefällt mir das Ergebnis nicht…

$bin = pack("f", $float);
echo $bin;

Ausgabe: ¶m½B


Vielleicht kann sich das ja mal jemand anschauen, der sich mit php auskennt.

Hier mal ein geloggter Befehl für z.B. den blauen Kanal (/1/blue ,f „irgendein Floatwert“):

2F 31 2F 62 6C 75 65 00 2C 66 00 00 41 A7 8C EB

Analog dazu gibt es die Kanäle /1/red und /1/green.

Viele Grüße und ein schönes Wochenende
Thilo

Hi Thilo,
ich habe gerade mal per google gesucht und auch ein wenig mit pack gespielt.
Leider kann ich nicht beurteilen wie das richtige Ergebnis aussehen muss.

Kennst Du diesen Link?
Open Sound Control for PHP | opensoundcontrol.org
Da sind für OSC passende Routinen enthalten um float zu packen, welche auch Little zu Big Endian berücksichtigen.

Grüße, Benjamin

Danke für die Antwort und deine Mühe.
Als erstes wäre mir schon geholfen, wenn ich per UDP z.B. den folgenden Hex-String ausgeben könnte, dann hätte ich erstmal die Möglichkeit, die RGB-LEDs überhaupt per IPS anzusteuern.

2F 31 2F 62 6C 75 65 00 2C 66 00 00 41 A7 8C EB  

Das Problem ist, das ich beim Senden von UDP mit USCK_SendText nur einen Text (ASCII) angeben kann, der dann aber als Hex gesendet wird.
OSC verwendet Füllzeichen (Hex 00, ASCII NUL), die ich nicht in die Zeichenfolge bekomme.

Das Problem mit der Umwandlung Float zu 4byte-Hex mit pack kann ich dann auch später noch weiterverfolgen.
Vielleicht hat dazu jemand einen Lösungsansatz, wie schon gesagt bin ich eher auf dem Gebiet der Hardware zu Haus eals bei php.

Viele Grüße
Thilo

Hum, Du kannst mit der Funktion chr einen beliebigen Ascii Code verwenden:

$test="test".chr(0)

Ich muesste mir also einen String zusammenbasteln, der vorn mit

2F 31 2F 62 6C 75 65

anfängt, dann chr(0), dann ,f (2C 66 Hex),danach wieder zweimal den chr(0)
und zum Abschluss die 4byte hex-float variable.
Und das ganze soll dann per udp versendet werden.
Wie schon geschrieben kann ich mit dem USCK_SendText ja schon den ersten Teil (/1/blue) senden. (laut debug-Fenster schickt IPS das Ganze auch raus).

Ich habs immer noch nicht begriffen, wie ich das machen soll…
Sorry, bin aber wie schon gesagt Hardwerker…
Danke für eure Hilfe
Thilo

z.B. so.

$string = "\x00\x00\x12\xF0..........................."; 

Danke für den schnellen Hinweis an @RWN,
ich hatte gerade die erste Reaktion meiner LEDs auf IPS (per udp und Arduino-Server):).
damit geht das Steuern per udp erstmal (rudimentär …) und ich muss „nur“ noch diese komische Umwandlung float zu 4-byte-hex mit pack hinkriegen.

Danke
Thilo

So, nochmal bei der großen Suchmaschine gesucht:

Ich benötige eine php-routine zum Umrechnen von float (0 bis 255) in eine IEEE754 - 4-byte-hex-variable, die dann als die 4 letzten Stellen an den Arduino-client ausgegeben werden.
D.h. der Hex-String geht von 00000000 (Wert 0) bis 437F0000 (Wert 255).

Nach dem IEEE754 Standard gibt es da eine komplizierte Umrechnung, aber vielleicht hat jemand sowas schonmal gemacht, um irgendwelche Zeichenketten auszugeben oder zu verarbeiten?

Viele Grüße
Thilo

Hallo Thilo,

im PHP Manual ist eine Beispiel:

LINK

Das 2. Beispiel
HTH
Attain

Wenn ich mit diesem Beispiel richtig liege (2.Beispiel von oben):

Converting IEEE754 64 bit binary to float in 32bit php version: 

ist das genau die umgekehrte Richtung von der die ich brauche.
Ich möchte im IPS einen float-wert von 0…255 pro Farbe auswählen und daraus müsste der IEEE754- 4byte-hex-wert erzeugt werden, der dann per udp an den Arduino gehen soll.

Danke für Deine Hilfe

Thilo

So, falls es jemanden interessiert:
ich habe die float2hex-function gefunden und sie funktioniert auch so wie gewünscht:

<?php

/** Complementary functions to CONVERT PHP FLOATING POINT NUMBERS or DECIMALS
 *  (IEEE 754 single-precision 32 bit) TO HEXADECIMAL AND BACK.
 *   
 *  @author NSTIAC (Jorge D. Baigorri Salas) <http://www.nstiac.com> <http://www.n2works.com>
 *  @created on 28/Jan/2010 / time spent: 2hours approx.
 *  @special thanks to Thomas Finley's article "Floating Point"
 *  <http://tfinley.net/notes/cps104/floating.html>
 *
 *  These functions allow to convert any php floating point numbers with the
 *  notation 1.234 (or fixed point numbers) into their corresponding 8 digits
 *  hexadecimal notation. (i.e.- 1557897.40 -> 49BE2C4B <- 1557897.40) by
 *  disregarding their implicit format and treating them at will as either
 *  integer, decimals, binary numbers, hexadecimal values, or plain text.
 *       
**/

/** FLOAT2HEX32n
  * (Convert php float numbers or decimals (single-precision 32bits) to 8 digit Hexadecimal)
  * Accepts only fixed point notation decimal numbers or fractions on a string (i.e.- "1.23456")
  * @usage:
  * float2hex32n("-1557897.13"); returns "c9be2c49"
**/

function float2hex32n($number) {
    //Convert non-decimal to decimal.
    $number=number_format($number,23,'.','');
    //Get the integer portion of $number   
    if ($number>0) {
        $intnumber=substr($number,0,strpos($number,"."));
    } else {
        //Check whether is a negative number to remove - sign.
        $intnumber=substr($number,1,strpos($number,"."));
    }
    //Convert integer to binary
    $binint=decbin($intnumber);
    //Get the decimal fraction of the number
    $pointnumber=substr($number,strpos($number,"."));
    //Add a 0 to treat as single decimal fraction
    $pointnumber="0".$pointnumber;
    //Convert decimal values to base 2
    $tmppoint=number_format($pointnumber*2,23,'.','');
    for ($i=0; $i<23; $i++) {
        $binpoint.=substr((string)$tmppoint,0,1);
        $tmppoint=substr((string)$tmppoint,1);
        $tmppoint=number_format($tmppoint*2,23,'.','');
    }
    //Gather both values to get base 2 binary fraction
    $scibin=$binint.".".$binpoint;
    //Find fraction separator "." position
    $exp=strpos($scibin,".");
    //Transform to scientific notation (1.x^exp)
    $scibin=substr($binint,0,1).".".substr($binint,1).$binpoint;
    //Create mantissa
    if ($scibin>1) {
        $mantissa=substr($scibin,2);
    } else {
        $mantissa=substr($scibin,1);
    }
    //Fill mantissa to 23 bit value
    $fill23=23-strlen($mantissa);
    for ($i=0; $i<$fill23; $i++) {
    $mantissa.="0";
    }
    //Convert fraction separator position to exponent value
    if ($exp>0) { $exp--; }
    //Adjust to binary notation exponent value
    $exp+=127;
    //Convert to 8 bit binary
    $exp=decbin($exp);
    //Find 1 bit sign value   
    if ($number>0) { $sign=0; } else { $sign=1; }
    //Compose final binary value
    $binfinal=$sign.$exp.$mantissa;
    //Reorganizae number into 4digit/bits packets and
    //finally convert to decimal value and to hex.
    $hexfinal.=dechex(bindec(substr($binfinal,0,4)));
    $hexfinal.=dechex(bindec(substr($binfinal,4,4)));
    $hexfinal.=dechex(bindec(substr($binfinal,8,4)));
    $hexfinal.=dechex(bindec(substr($binfinal,12,4)));
    $hexfinal.=dechex(bindec(substr($binfinal,16,4)));
    $hexfinal.=dechex(bindec(substr($binfinal,20,4)));
    $hexfinal.=dechex(bindec(substr($binfinal,24,4)));
    $hexfinal.=dechex(bindec(substr($binfinal,28,4)));

    return $hexfinal;
}

/** Using either function will return a value which can be used on the other function
  * to return the original input. (Hope it helps =)
**/

?> 

Jetzt heisst es „nur“ noch den string zur Ausgabe per udp zu generieren und da die erzeugten Werte einsetzen. D.h. ich habe einen festen Teil des Strings (2F 31 2F 62 6C 75 65 00 2C 66 00 00) und danach müsste ich die erzeugten 4 variablen Hex-Werte anfügen. Wenn jemand dazu einen Denkanstoss hat, wäre ich sehr dankbar. Ansonsten nimmt die ganze Geschichte so langsam Gestalt an.
Vielen Dank für eure Mitarbeit

Viele Grüße
Thilo

Einfach mit . anhängen.

$test = $string.$string;

Perfekt, Danke, das bringt mich weiter…

Viele Grüße
Thilo

Kann ich den erzeugten Hex-String irgendwie auseinandernehmen (aus 4236e344 wird dann $string1 = 42, $string2 = 36 usw.), da ich ja den zu sendenden String in der hex-Ausführung schreiben muss (\x42\x36 usw.)?

Beispiel:
Wenn ich diesen String schicke, geht die rote LED an.

$rotan = "\x2F\x31\x2F\x72\x65\x64\x00\x00\x2C\x66\x00\x00\x43\x7F\x00\x00";

dabei sind die letzten 4 byte die Helligkeitswerte.
Diese generiere ich ja jetzt durch die float2hex32n-funktion, muss sie aber noch in die richtige Form bringen (\x43\x7F\x00\x00) und dann mit einem festen String „\x2F\x31\x2F\x72\x65\x64\x00\x00\x2C\x66\x00\x00“ verheiraten.
Das müsste dann mit $string.$string funktionieren.

Danke
Thilo

Nicht schön aber funktionell. :slight_smile:

$string = "4236e344";
echo "\x".substr($string, 0,2)."\x".substr($string, -6,-4)."\x".substr($string, -4,-2)."\x".substr($string, -2);

Andere Alternative für deine Zwecke.

$string = "4236e344";
$string = preg_replace('/([\d\D]{2})([\d\D]{2})([\d\D]{2})([\d\D]{2})/', '\x$1\x$2\x$3\x$4', $string);
echo $string;

Normal, würde ich dafür aber eine Function schreiben.:wink:

Danke für die Vorschläge zum Zusammenfügen und Umwandeln.
Irgendwo ist da noch der Wurm drin, nach dem Zusammenfügen der beiden strings ergibt sich folgende Ausgabe:

Von der ersten Variable (konstant): 2F 31 2F 62 6C 75 65 00 2C 66 00 00
ist ok.
Von der 2 Variable (Helligkeitswert): 5C 78 34 33 5C 78 37 46 5C 78 30 30 5C 78 30 30
Hier wandelt er die \x in ASCII um…und nimmt sie nicht als Hex-Wert.

Darf ich nochmal um Hilfe bitten?

Dankeschön im voraus
Thilo

Hier wandelt er die \x in ASCII um…und nimmt sie nicht als Hex-Wert.

Wer wandelt das um? \x wird nicht umgewandelt, das ist nur die Schreibweise.

Alternativ kannst Du auch mit chr operieren.

$string = „\xff\xff“; ist das selbe wie chr(0xff).chr(0xff);

Ich habe jetzt folgendes getestet:

<?

$string = "437F0000";
$string = preg_replace('/([\d\D]{2})([\d\D]{2})([\d\D]{2})([\d\D]{2})/', '\x$1\x$2\x$3\x$4', $string);
//echo $string;

$blauan = "\x2F\x31\x2F\x62\x6C\x75\x65\x00\x2C\x66\x00\x00";
$Summe = $blauan.$string;
//echo $Summe;
USCK_SendText(50261 /*[UDP Socket]*/,"$Summe");
?>

Und per debug gibt er dann die 20 byte aus:
2F 31 2F 62 6C 75 65 00 2C 66 00 00 5C 78 34 33 5C 78 37 46 5C 78 30 30 5C 78 30 30
Bis zur 66 00 00 stimmt das Ganze, danach läuft was schief.

Viele Grüße
Thilo

probier es mal so.

<? 
 
$string = "437F0000"; 
$string = preg_replace('/([\d\D]{2})([\d\D]{2})([\d\D]{2})([\d\D]{2})/', '\x$1\x$2\x$3\x$4', $string); 
//echo $string; 
 
$blauan = '\x2F\x31\x2F\x62\x6C\x75\x65\x00\x2C\x66\x00\x00'; 
$Summe = $blauan.$string; 
//echo $Summe; 
USCK_SendText(50261 /*[UDP Socket]*/, $Summe); 
?>    

Debug-Ausgabe:

5C 78 32 46 5C 78 33 31 5C 78 32 46 5C 78 36 32 5C 78 36 43 5C 78 37 35 5C 78 36 35 5C 78 30 30 5C 78 32 43 5C 78 36 36 5C 78 30 30 5C 78 30 30 5C 78 34 33 5C 78 37 46 5C 78 30 30 5C 78 30 30 

Der Wurm ist immer noch drin…jetzt ist er sogar größer geworden. :slight_smile:

Also mit " war schon gut…

Viele Grüße
Thilo