|
From: <ma...@us...> - 2011-10-17 23:52:21
|
Revision: 454
http://openautomation.svn.sourceforge.net/openautomation/?rev=454&view=rev
Author: makki1
Date: 2011-10-17 23:52:15 +0000 (Mon, 17 Oct 2011)
Log Message:
-----------
russconnectd: interims commit, WiP
Modified Paths:
--------------
tools/russconnectd/trunk/ChangeLog
tools/russconnectd/trunk/README
tools/russconnectd/trunk/debian/docs
tools/russconnectd/trunk/russ_galist.ods
tools/russconnectd/trunk/src/main.c
Added Paths:
-----------
tools/russconnectd/trunk/cfgmaker.pl
Modified: tools/russconnectd/trunk/ChangeLog
===================================================================
--- tools/russconnectd/trunk/ChangeLog 2011-10-17 21:07:20 UTC (rev 453)
+++ tools/russconnectd/trunk/ChangeLog 2011-10-17 23:52:15 UTC (rev 454)
@@ -1,6 +1,8 @@
*** 0.2 - 2011-10-15
- global UDP-socket sending with listen port as source to make socat happy
-- parse partial/fragmented messages from Russound
+- parse partial/fragmented messages from Russound (WiP still pending fragments with multiple msg)
+- change DPT for Bass,Treble,Balance from 5.010 (uchar) to DPT 6.001 (signed char -10 .. +10)
+- small additions and fixes
*** 0.1
-- initial release, see README
\ No newline at end of file
+- initial release, see README
Modified: tools/russconnectd/trunk/README
===================================================================
--- tools/russconnectd/trunk/README 2011-10-17 21:07:20 UTC (rev 453)
+++ tools/russconnectd/trunk/README 2011-10-17 23:52:15 UTC (rev 454)
@@ -36,5 +36,6 @@
*** Outlook
- *maybe* make much more modular and other interfaces (simple UDP/TCP server like C0 Z1 VolUp?)
+-> implement RIO protocal partially
- don't depend on libeibclient then
- *maybe* add outgoing interfaces for KNX-> mpd,vdr,.. to stick multiroom togehter
Added: tools/russconnectd/trunk/cfgmaker.pl
===================================================================
--- tools/russconnectd/trunk/cfgmaker.pl (rev 0)
+++ tools/russconnectd/trunk/cfgmaker.pl 2011-10-17 23:52:15 UTC (rev 454)
@@ -0,0 +1,228 @@
+#!/usr/bin/perl
+use strict;
+
+my $ZONES_PER_CONTROLLER = 6; #static
+my @gfuncnames = qw(SetAllZonesPower WRITEONLYACT NA3 NA4 NA5 AllZonesPowerState);
+my @funcnames = qw(SetPower SetSource SetVol SetBass SetTreble SetLoudness SetBalance SetParty SetDnD SetOnVol SourceSetCMD SourceKeypadCMD SetVolRelative);
+my @statenames = qw(PowerState SourceSelected VolumeState BassState TrebleState LoudnessState BalanceState PartyState DnDState OnVolState);
+my $NamePrefix = "Multiroom";
+my @SourceNames = qw(UKW-Tuner vdr/mpd Denon-WZ WG1 WG2 Hobby);
+### End config - Don't change below ###
+#######################################
+
+use File::Copy;
+use Config::Tiny;
+#print "install libconfig-tiny-perl!";
+use Getopt::Std;
+use Data::Dumper;
+use XML::Simple;
+getopts("a:z:n:f:", \my %opts);
+my $conf = Config::Tiny->new;
+
+my @funcdpts = qw (1.001 5.010 5.001 6.001 6.001 1.001 6.001 1.001 1.001 5.001 5.010 5.010 1.008);
+my @funcdpts_sub = qw (DPT_Switch DPT_Value_1_Ucount DPT_Scaling DPT_Percent_V8 DPT_Percent_V8 DPT_Switch DPT_Percent_V8 DPT_Switch DPT_Switch DPT_Scaling DPT_Value_1_Ucount DPT_Value_1_Ucount DPT_UpDown);
+my @statedpts = qw(1.001 5.010 5.001 6.001 6.001 1.001 6.001 1.001 1.001 5.001);
+my @statedpts_sub = qw (DPT_Switch DPT_Value_1_Ucount DPT_Scaling DPT_Percent_V8 DPT_Percent_V8 DPT_Switch DPT_Percent_V8 DPT_Switch DPT_Switch DPT_Scaling);
+
+my %EISmap = (
+ 1.001 => "EIS 1 'Switching' (1 Bit)",
+ 1.008 => "EIS 1 'Switching' (1 Bit)",
+ 5.001 => "Uncertain (1 Byte)",
+ 5.010 => "Uncertain (1 Byte)",
+ 6.001 => "Uncertain (1 Byte)" );
+
+if (!$opts{a} or !$opts{z} or !$opts{n} or $opts{h}) {
+ print("\n$0 Tool to create GA-config\nUsage: $0 -a <startaddress> -z <zones> -n <name1,name2,...>\n"
+ . "Example: $0 -a 10/1/0 -z 6 -n Küche,Bad,Zone3,Zone4,Zone5,Zone6 >> /etc/wiregate/eibga.conf\n"
+ . "Optional to write new config in-place: -f <path-to-eibga.conf> - Example: -f /etc/wiregate/eibga.conf\n");
+ exit();
+}
+
+if (-e $opts{f}) {
+ $conf = Config::Tiny->read($opts{f});
+ print STDERR "read config $opts{f}\n";
+}
+
+my @zonenames = split(",",$opts{n});
+my $startga = str2addr($opts{a},1);
+
+# ESF output for poor guys
+open ESF, ">", "export.esf" or die $!;
+open XML, ">:encoding(UTF-8)", "linknx.xml" or die $!;
+
+# some visu_config snipplet for CometVisu - :encoding(UTF-8)??
+open VISU1, ">", "visu_snipplet_rooms.xml" or die $!;
+open VISU2, ">", "visu_snipplet_room_pages.xml" or die $!;
+open VISU3, ">", "visu_snipplet_room_pages_all.xml" or die $!;
+
+print VISU1 " <page name=\"$NamePrefix\">\n";
+
+# Globals
+$conf->{addr2str($startga+1,1)}->{'name'} = $NamePrefix . " " . $gfuncnames[0];
+$conf->{addr2str($startga+1,1)}->{'DPTSubId'} = 1.001;
+$conf->{addr2str($startga+1,1)}->{'DPTId'} = 1;
+#$conf->{addr2str($startga+1,1)}->{'DPT_SubTypeName'} = 'DPT_Switch';
+print ESF "Multiroom-export\n";
+print ESF "$NamePrefix.Controller." . addr2str($startga+1,1) . "\t$NamePrefix $gfuncnames[0]\t" . $EISmap{'1.001'} . "\tLow\n";
+
+print XML "#<?xml version=\"1.0\" ?>\n<config>\n\t<objects>\n";
+print XML "\t\t<object id=\"$NamePrefix"."_$gfuncnames[0]\" gad=\"" . addr2str($startga+1,1) . "\" type=\"1.001\">$NamePrefix $gfuncnames[0]</object>\n";
+
+for (my $zone=0;$zone<$opts{z};$zone++) {
+ #sendKNXdgram (0x80,1,(knxstartaddress+30)+(zone*40)+(controller*256),val);
+ my $ctrl = int($zone/$ZONES_PER_CONTROLLER);
+ my $czone = int($zone%$ZONES_PER_CONTROLLER);
+ my $basega = $startga+10 + ($czone*40) + ($ctrl*256);
+ my $basegastr = addr2str($basega,1);
+ print STDERR "Zone " . ($zone+1) . " is $zonenames[$zone] base: $basegastr\n";
+ # funcs
+ for (my $i=0;$i<$#funcnames+1;$i++) {
+ $conf->{addr2str($basega+$i,1)}->{'name'} = "$NamePrefix C" . ($ctrl+1) . "-Z" . ($czone+1) . " $zonenames[$zone] $funcnames[$i]";
+ $conf->{addr2str($basega+$i,1)}->{'DPTSubId'} = $funcdpts[$i];
+ $conf->{addr2str($basega+$i,1)}->{'DPTId'} = split(".",$funcdpts[$i],1);
+ #$conf->{addr2str($basega+$i,1)}->{'DPT_SubTypeName'} = $funcdpts_sub[$i];
+ print ESF "$NamePrefix.Controller$ctrl." . addr2str($basega+$i,1) . "\t" . "$NamePrefix $zonenames[$zone] C" . ($ctrl+1) . "-Z" . ($czone+1) . " $funcnames[$i]" . "\t" . $EISmap{$funcdpts[$i]} . "\tLow\n";
+ print XML "\t\t<object id=\"$zonenames[$zone]_C" . ($ctrl+1) . "_Z" . ($czone+1) . "_" . "$funcnames[$i]\" gad=\"" . addr2str($basega+$i,1) . "\" type=\"$funcdpts[$i]\">" . "$NamePrefix $zonenames[$zone] (C" . ($ctrl+1) . "/Z" . ($czone+1) . ") $funcnames[$i]" . "</object>\n";
+ }
+ #states
+ for (my $i=0;$i<$#statenames+1;$i++) {
+ $conf->{addr2str($basega+$i+20,1)}->{'name'} = "$NamePrefix C" . ($ctrl+1) . "-Z" . ($czone+1) . " $zonenames[$zone] $statenames[$i]";
+ $conf->{addr2str($basega+$i+20,1)}->{'DPTSubId'} = $statedpts[$i];
+ $conf->{addr2str($basega+$i+20,1)}->{'DPTId'} = split(".",$statedpts[$i],1);
+ #$conf->{addr2str($basega+$i+20,1)}->{'DPT_SubTypeName'} = $statedpts_sub[$i];
+ print ESF "$NamePrefix.Controller$ctrl." . addr2str($basega+$i+20,1) . "\t" . "$NamePrefix $zonenames[$zone] C" . ($ctrl+1) . "-Z" . ($czone+1) . " $statenames[$i]" . "\t" . $EISmap{$statedpts[$i]} . "\tLow\n";
+ print XML "\t\t<object id=\"$zonenames[$zone]_C" . ($ctrl+1) . "_Z" . ($czone+1) . "_" . "$statenames[$i]\" gad=\"" . addr2str($basega+$i+20,1) . "\" type=\"$statedpts[$i]\">" . "$NamePrefix $zonenames[$zone] (C" . ($ctrl+1) . "/Z" . ($czone+1) . ") $statenames[$i]" . "</object>\n";
+ }
+ print VISU1 ' <switch mapping="OnOff" styling="RedGreen">'
+ ."\n <label>$zonenames[$zone]</label>\n"
+ .' <address transform="DPT:1.001" readonly="false" type="">' . addr2str($basega,1) . "</address>\n"
+ .' <address transform="DPT:1.001" readonly="true" type="">' . addr2str($basega+20,1) . "</address>\n"
+ ." </switch>\n";
+ print VISU1 ' <slide min="0" max="100">'
+ ."\n <label>$zonenames[$zone] Vol</label>\n"
+ .' <address transform="DPT:5.001" readonly="false" type="">' . addr2str($basega+2,1) . "</address>\n"
+ .' <address transform="DPT:5.001" readonly="true" type="">' . addr2str($basega+22,1) . "</address>\n"
+ ." </slide>\n";
+ print VISU2 " <page name=\"$NamePrefix $zonenames[$zone]\">\n";
+ print VISU2 ' <switch mapping="OnOff" styling="RedGreen">'
+ ."\n <label>Power</label>\n"
+ .' <address transform="DPT:1.001" readonly="false" type="">' . addr2str($basega,1) . "</address>\n"
+ .' <address transform="DPT:1.001" readonly="true" type="">' . addr2str($basega+20,1) . "</address>\n"
+ ." </switch>\n";
+ print VISU2 ' <slide min="0" max="100">'
+ ."\n <label>Vol</label>\n"
+ .' <address transform="DPT:5.001" readonly="false" type="">' . addr2str($basega+2,1) . "</address>\n"
+ .' <address transform="DPT:5.001" readonly="true" type="">' . addr2str($basega+22,1) . "</address>\n"
+ ." </slide>\n";
+ print VISU2 ' <info format="">'
+ ."\n <label>Source</label>\n"
+ .' <address transform="DPT:5.010" readonly="false" type="">' . addr2str($basega+1,1) . "</address>\n"
+ .' <address transform="DPT:5.010" readonly="true" type="">' . addr2str($basega+21,1) . "</address>\n"
+ ." </info>\n";
+ print VISU2 " <multitrigger button1label=\"$SourceNames[0]\" button1value=\"0\" button2label=\"$SourceNames[1]\" button2value=\"1\" button3label=\"$SourceNames[2]\" button3value=\"2\" button4label=\"$SourceNames[3]\" button4value=\"3\">"
+ ."\n <label>Source</label>\n"
+ .' <address transform="DPT:5.010" readonly="false" type="">' . addr2str($basega+1,1) . "</address>\n"
+ .' <address transform="DPT:5.010" readonly="true" type="">' . addr2str($basega+21,1) . "</address>\n"
+ ." </multitrigger>\n";
+ print VISU2 " <multitrigger button1label=\"$SourceNames[4]\" button1value=\"4\" button2label=\"$SourceNames[5]\" button2value=\"5\">"
+ ."\n <label>Source</label>\n"
+ .' <address transform="DPT:5.010" readonly="false" type="">' . addr2str($basega+1,1) . "</address>\n"
+ .' <address transform="DPT:5.010" readonly="true" type="">' . addr2str($basega+21,1) . "</address>\n"
+ ." </multitrigger>\n";
+ print VISU2 ' <switch mapping="OnOff" styling="RedGreen">'
+ ."\n <label>Loudness</label>\n"
+ .' <address transform="DPT:1.001" readonly="false" type="">' . addr2str($basega+5,1) . "</address>\n"
+ .' <address transform="DPT:1.001" readonly="true" type="">' . addr2str($basega+25,1) . "</address>\n"
+ ." </switch>\n";
+ print VISU2 ' <infotrigger button1label="+" button1value="1" button2label="-" button2value="0" align="center" infoposition="1" format="%.0f %%">'
+ ."\n <label>Volume</label>\n"
+ .' <address transform="DPT:1.008" readonly="false" type="">' . addr2str($basega+12,1) . "</address>\n"
+ .' <address transform="DPT:5.001" readonly="true" type="">' . addr2str($basega+2,1) . "</address>\n"
+ .' <address transform="DPT:5.001" readonly="true" type="">' . addr2str($basega+22,1) . "</address>\n"
+ ." </infotrigger>\n";
+ print VISU2 ' <info format="%.0f %%">'
+ ."\n <label>TurnOn Vol</label>\n"
+ .' <address transform="DPT:5.001" readonly="false" type="">' . addr2str($basega+9,1) . "</address>\n"
+ .' <address transform="DPT:5.001" readonly="true" type="">' . addr2str($basega+29,1) . "</address>\n"
+ ." </info>\n";
+ print VISU2 ' <slide min="0" max="100">'
+ ."\n <label>TurnOn Vol</label>\n"
+ .' <address transform="DPT:5.001" readonly="false" type="">' . addr2str($basega+9,1) . "</address>\n"
+ .' <address transform="DPT:5.001" readonly="true" type="">' . addr2str($basega+29,1) . "</address>\n"
+ ." </slide>\n";
+ print VISU2 ' <slide min="-10" max="10">'
+ ."\n <label>Bass</label>\n"
+ .' <address transform="DPT:6.001" readonly="false" type="">' . addr2str($basega+3,1) . "</address>\n"
+ .' <address transform="DPT:6.001" readonly="true" type="">' . addr2str($basega+23,1) . "</address>\n"
+ ." </slide>\n";
+ print VISU2 ' <slide min="-10" max="10">'
+ ."\n <label>Treble</label>\n"
+ .' <address transform="DPT:6.001" readonly="false" type="">' . addr2str($basega+4,1) . "</address>\n"
+ .' <address transform="DPT:6.001" readonly="true" type="">' . addr2str($basega+24,1) . "</address>\n"
+ ." </slide>\n";
+ print VISU2 ' <slide min="-10" max="10">'
+ ."\n <label>Balance</label>\n"
+ .' <address transform="DPT:6.001" readonly="false" type="">' . addr2str($basega+6,1) . "</address>\n"
+ .' <address transform="DPT:6.001" readonly="true" type="">' . addr2str($basega+26,1) . "</address>\n"
+ ." </slide>\n";
+ print VISU2 ' <switch mapping="OnOff" styling="RedGreen">'
+ ."\n <label>Party</label>\n"
+ .' <address transform="DPT:1.001" readonly="false" type="">' . addr2str($basega+7,1) . "</address>\n"
+ .' <address transform="DPT:1.001" readonly="true" type="">' . addr2str($basega+27,1) . "</address>\n"
+ ." </switch>\n";
+ print VISU2 ' <switch mapping="OnOff" styling="RedGreen">'
+ ."\n <label>DnD</label>\n"
+ .' <address transform="DPT:1.001" readonly="false" type="">' . addr2str($basega+8,1) . "</address>\n"
+ .' <address transform="DPT:1.001" readonly="true" type="">' . addr2str($basega+28,1) . "</address>\n"
+ ." </switch>\n";
+ print VISU2 " </page>\n";
+}
+
+close ESF;
+print XML "\t</objects>\n</config>\n";
+close XML;
+
+print VISU1 " </page>\n";
+close VISU1;
+close VISU2;
+close VISU3;
+
+#print "CONF:" . Dumper($conf);
+if (-e $opts{f}) { # wite config in place
+ copy($opts{f},$opts{f} . '.bak' );
+ $conf->write( $opts{f} . '.new' );
+ move( $opts{f} . '.new',$opts{f} );
+} else { # dump to STDOUT
+ $conf->write( '-' );
+}
+
+######
+# END
+######
+### copied global funcs
+# addr2str: Convert an integer to an EIB address string, in the form "1/2/3" or "1.2.3"
+sub addr2str {
+ my $a = $_[0];
+ my $b = $_[1] || 0; # 1 if local (group) address, else physical address
+ my $str ;
+ if ($b == 1) { # logical address used
+ $str = sprintf "%d/%d/%d", ($a >> 11) & 0xf, ($a >> 8) & 0x7, $a & 0xff;
+ }
+ else { # physical address used
+ $str = sprintf "%d.%d.%d", $a >> 12, ($a >> 8) & 0xf, $a & 0xff;
+ }
+ return $str;
+}
+
+# str2addr: Convert an EIB address string in the form "1/2/3" or "1.2.3" to an integer
+sub str2addr {
+ my $str = $_[0];
+ if ($str =~ /(\d+)\/(\d+)\/(\d+)/) { # logical address
+ return ($1 << 11) | ($2 << 8) | $3;
+ } elsif ($str =~ /(\d+)\.(\d+)\.(\d+)/) { # physical address
+ return ($1 << 12) | ($2 << 8) | $3;
+ } else {
+ #bad
+ return;
+ }
+}
Property changes on: tools/russconnectd/trunk/cfgmaker.pl
___________________________________________________________________
Added: svn:executable
+ *
Modified: tools/russconnectd/trunk/debian/docs
===================================================================
--- tools/russconnectd/trunk/debian/docs 2011-10-17 21:07:20 UTC (rev 453)
+++ tools/russconnectd/trunk/debian/docs 2011-10-17 23:52:15 UTC (rev 454)
@@ -1,4 +1,5 @@
NEWS
README
russ_galist.ods
+cfgmaker.pl
Modified: tools/russconnectd/trunk/russ_galist.ods
===================================================================
(Binary files differ)
Modified: tools/russconnectd/trunk/src/main.c
===================================================================
--- tools/russconnectd/trunk/src/main.c 2011-10-17 21:07:20 UTC (rev 453)
+++ tools/russconnectd/trunk/src/main.c 2011-10-17 23:52:15 UTC (rev 454)
@@ -38,17 +38,18 @@
#define DEBUG 1
#define DAEMON_NAME "russconnectd"
-#define USAGESTRING "\n\t-d\tRun as daemon/No debug output\n\t-p <pidfile>\tPID-filename\n\t-i <ip:port>\tIP-Address:Port to send UDP-packets to russound\n\t-l <UDP-port>\tUDP port to listen on\n\t-a <KNX address>\tKNX start-address (see README)\n\t-z <number>\tNumber of Zones to support\n\t-u <eib url>\tURL to conatct eibd like localo:/tmp/eib or ip:192.168.0.101\n"
+#define USAGESTRING "\n\t-d\tRun as daemon/No debug output\n\t-p <pidfile>\tPID-filename\n\t-i <ip:port>\tIP-Address:Port to send UDP-packets to russound\n\t-l <UDP-port>\tUDP port to listen on\n\t-a <KNX address>\tKNX start-address (see README)\n\t-z <number>\tNumber of Zones to support\n\t-u <eib url>\tURL to conatct eibd like localo:/tmp/eib or ip:192.168.0.101\n\t-s\t(Optional) send all values to KNX on startup of daemon\n"
#define NUM_THREADS 2
#define MAX_ZONES 31
#define RETRY_TIME 5
#define BUFLEN 1024
-#define POLLING_INTERVAL 60
+#define POLLING_INTERVAL 10
#define ZONES_PER_CONTROLLER 6
#define RUSS_KEYPAD_ID 0x70
pthread_mutex_t zonelock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t initlock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t standbylock = PTHREAD_MUTEX_INITIALIZER;
//FIXME:make struct zone dynamic
typedef struct Zone_t {
@@ -79,6 +80,7 @@
int numzones = ZONES_PER_CONTROLLER;
int pidFilehandle;
char *pidfilename = "/var/run/russconnectd.pid";
+int sendOnStart = 0;
//FIXME: also handle serial-port directly?
struct sockaddr_in si_me, si_other;
@@ -137,6 +139,7 @@
void *sendrussPolling(unsigned char zone) {
syslog(LOG_DEBUG, "polling zone %d",zone);
+ pthread_mutex_trylock(&standbylock);
char buf_onvol[25] = { 0xF0, 0, 0, 0x7F, 0, 0, RUSS_KEYPAD_ID, 0x01, 0x05, 0x02, 0, 0, 0, 0x04, 0, 0, 0, 0xF7 };
buf_onvol[1] = zone/ZONES_PER_CONTROLLER;
buf_onvol[11] = zone%ZONES_PER_CONTROLLER;
@@ -158,8 +161,12 @@
void *sendrussFunc(int controller, int zone, int func, int val) {
syslog(LOG_DEBUG,"write ctrl %d zone %d func %d val 0x%02X",controller,zone,func,val);
-
+
//TODO: send on-telegram to actuator
+
+ //block here until something is received from russound (it's turned off)
+ pthread_mutex_lock(&standbylock);
+ pthread_mutex_unlock(&standbylock);
char buf_msg1[25] = { 0, 0, 0, 0x7F, 0, 0, RUSS_KEYPAD_ID, 0x05, 0x02, 0x02, 0, 0, 0xF1, 0x23, 0, 0, 0, 0, 0, 0x01, 0, 0xF7 };
buf_msg1[1] = controller;
buf_msg1[17] = zone;
@@ -207,7 +214,10 @@
case 6: //bal
buf_msg2[0] = 0xF0;
buf_msg2[13] = 0x03;
- buf_msg2[21] = val;
+ if (val>127)
+ buf_msg2[21] = val-256+10;
+ else
+ buf_msg2[21] = val+10;
break;
case 7: //party
buf_msg2[0] = 0xF0;
@@ -298,6 +308,12 @@
buf[2] = val;
len=3;
break;
+ case 6:
+ case 6001:
+ //FIXME: This is basically wrong but as we get a uchar we expect the sender to know..
+ buf[2] = val;
+ len=3;
+ break;
/*
case 9:
fval=atof(data);
@@ -351,11 +367,17 @@
break;
case 3:
case 23:
- sendKNXdgram (0x40,51,dest,zones[zone].bass);
+ if (zones[zone].bass<10)
+ sendKNXdgram (0x40,51,dest,zones[zone].bass-10+256);
+ else
+ sendKNXdgram (0x40,51,dest,zones[zone].bass-10);
break;
case 4:
case 24:
- sendKNXdgram (0x40,51,dest,zones[zone].treble);
+ if (zones[zone].treble<10)
+ sendKNXdgram (0x40,51,dest,zones[zone].treble-10+256);
+ else
+ sendKNXdgram (0x40,51,dest,zones[zone].treble-10);
break;
case 5:
case 25:
@@ -363,7 +385,10 @@
break;
case 6:
case 26:
- sendKNXdgram (0x40,51,dest,zones[zone].balance);
+ if (zones[zone].balance<10)
+ sendKNXdgram (0x40,51,dest,zones[zone].balance-10+256);
+ else
+ sendKNXdgram (0x40,51,dest,zones[zone].balance-10);
break;
case 27:
sendKNXdgram (0x40,1,dest,zones[zone].partymode);
@@ -467,7 +492,7 @@
syslog(LOG_DEBUG, "update Zone %d val %d func %d",num,val,func);
int controller = num/ZONES_PER_CONTROLLER;
int zone = num%ZONES_PER_CONTROLLER;
- //TODO IMPORTANT!: lock mutex befor updating
+ //lock mutex befor updating
pthread_mutex_lock (&zonelock);
switch (func) {
case 1:
@@ -487,13 +512,21 @@
break;
case 4:
zones[num].bass =val;
- if (zones[num].inited)
- sendKNXdgram (0x80,51,(knxstartaddress+33)+(zone*40)+(controller*256),val);
+ if (zones[num].inited) {
+ if (val<10)
+ sendKNXdgram (0x80,51,(knxstartaddress+33)+(zone*40)+(controller*256),val-10+256);
+ else
+ sendKNXdgram (0x80,51,(knxstartaddress+33)+(zone*40)+(controller*256),val-10);
+ }
break;
case 5:
zones[num].treble =val;
- if (zones[num].inited)
- sendKNXdgram (0x80,51,(knxstartaddress+34)+(zone*40)+(controller*256),val);
+ if (zones[num].inited) {
+ if (val<10)
+ sendKNXdgram (0x80,51,(knxstartaddress+34)+(zone*40)+(controller*256),val-10+256);
+ else
+ sendKNXdgram (0x80,51,(knxstartaddress+34)+(zone*40)+(controller*256),val-10);
+ }
break;
case 6:
zones[num].loudness =val;
@@ -502,8 +535,12 @@
break;
case 7:
zones[num].balance =val;
- if (zones[num].inited)
- sendKNXdgram (0x80,51,(knxstartaddress+36)+(zone*40)+(controller*256),val);
+ if (zones[num].inited) {
+ if (val<10)
+ sendKNXdgram (0x80,51,(knxstartaddress+36)+(zone*40)+(controller*256),val-10+256);
+ else
+ sendKNXdgram (0x80,51,(knxstartaddress+36)+(zone*40)+(controller*256),val-10);
+ }
break;
case 8:
zones[num].partymode =val;
@@ -527,113 +564,134 @@
return 0;
}
+void *parseRussMsg(unsigned char* buf, int len) {
+ int i;
+ if ((len==34) && (buf[0]==0xF0) && (buf[9]==0x04)) { //zone-status
+ syslog(LOG_DEBUG,"russ Controller:%d Zone:%d Status:%d src:%d vol:%d bass:%d treb:%d loud:%d bal:%d sys:%d shrsrc:%d party:%d,DnD:%d\n",
+ buf[4],buf[12],buf[20],buf[21],buf[22],buf[23],buf[24],buf[25],buf[26],buf[27],buf[28],buf[29],buf[30]);
+ buf[12] = (buf[4]*ZONES_PER_CONTROLLER)+buf[12]; //controller + zonenumber
+ if (sendOnStart)
+ zones[buf[12]].inited = 1;
+
+ if (buf[20] != zones[buf[12]].zonepower)
+ updateZone(buf[12],buf[20],1);
+ if (buf[21] != zones[buf[12]].srcid)
+ updateZone(buf[12],buf[21],2);
+ if (buf[22] != zones[buf[12]].volume)
+ updateZone(buf[12],buf[22],3);
+ if (buf[23] != zones[buf[12]].bass)
+ updateZone(buf[12],buf[23],4);
+ if (buf[24] != zones[buf[12]].treble)
+ updateZone(buf[12],buf[24],5);
+ if (buf[25] != zones[buf[12]].loudness)
+ updateZone(buf[12],buf[25],6);
+ if (buf[26] != zones[buf[12]].balance)
+ updateZone(buf[12],buf[26],7);
+ if (buf[29] != zones[buf[12]].partymode)
+ updateZone(buf[12],buf[29],8);
+ if (buf[30] != zones[buf[12]].dnd)
+ updateZone(buf[12],buf[30],9);
+ zones[buf[12]].inited = 1;
+ } else if ((len==24) && (buf[0]==0xF0) && (buf[9]==0x05) && (buf[13]==0x00)) { //zone turn-on volume
+ //FIXME: this *might* be wrong andf trigger also on other msgs, as it's written otherwise in the docs, the checked bytes are just a guess!
+ syslog(LOG_DEBUG,"russ Controller:%d Zone:%d TurnOnVolume:%d",
+ buf[4],buf[12],buf[21]);
+ buf[12] = (buf[4]*ZONES_PER_CONTROLLER)+buf[12]; //controller + zonenumber
+ if (buf[21] != zones[buf[12]].onvolume)
+ updateZone(buf[12],buf[21],10);
+ } else {
+ //FIXME: just for debugging
+ //for (i=0; i<len; i++)
+ // printf("%d:0x%02X ",i,buf[i]);
+ printf(" unknown len: %d ",len);
+ for (i=0; i<len; i++)
+ printf("0x%02X ",buf[i]);
+ printf("\n");
+ }
+ return 0;
+}
+
void *russhandler()
{
- int i;
+ int cflag,worked;
unsigned char buf[BUFLEN];
unsigned char prevbuf[BUFLEN];
int prevlen = 0;
syslog(LOG_DEBUG, "Russound reader thread started");
while (1) {
+ //unlock standby-mutex as we received something
+ pthread_mutex_unlock(&standbylock);
int len = recvfrom(udpSocket, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen);
if (len==-1) {
syslog(LOG_WARNING, "russ: recvfrom failed");
sleep(RETRY_TIME);
break;
}
+
/* Stick together fragmented telegrams, start is F0, end is F7
- */
//FIXME: we assume either complete telegrams or fragmented but no overlapping messages in sep. udp dgrams!
-
- //DEBUG
+ int i,pos;
+
//for (i=0; i<len; i++)
// printf("PRE-parse: %d:0x%02X ",i,buf[i]);
printf( "PRE-Parse: %d -> ",len);
for (i=0; i<len; i++)
printf( "0x%02X ",buf[i]);
printf( "\n");
- //END DEBUG code
+ */
if ((len + prevlen) > BUFLEN) {
syslog(LOG_INFO, "Message too large: %d + %d !!",len,prevlen);
prevlen=0;
continue;
}
- if (buf[0] == 0xF0 && buf[len-1] == 0xF7) { // complete message
- syslog(LOG_DEBUG, "----> COMPLETE <---- message received, size %d \n", len);
- } else if (buf[0] == 0xF0) { // start of new message
- printf("..START..\n");
- prevlen = len;
- memcpy(prevbuf,buf,len);
+ worked = 0;
+ //while (worked < len) {
+ if (buf[0] == 0xF0 && buf[len-1] == 0xF7) { // complete message
+ syslog(LOG_DEBUG, "----> COMPLETE <---- message received, size %d \n", len);
+ } else if (buf[0] == 0xF0) { // start of new message
+ //printf("..START..\n");
+ prevlen = len;
+ worked += len;
+ memcpy(prevbuf,buf,len);
+ cflag = 1;
+ continue;
+ } else if (prevlen > 0 && prevbuf[0] == 0xF0 && buf[len-1] == 0xF7) { // message complete
+ //printf("..complete..%d %d\n",prevlen,len);
+ memcpy(prevbuf+prevlen,buf,len);
+ len += prevlen;
+ prevlen = 0;
+ memcpy(buf,prevbuf,len);
+ } else if (prevlen > 0 && prevbuf[0] == 0xF0) { //continuation message
+ //printf("..continue..%d %d\n",prevlen,len);
+ memcpy(prevbuf+prevlen,buf,len);
+ prevlen += len;
+ worked += len;
+ cflag = 1;
+ continue;
+ } else { //DUNNO!!
+ syslog(LOG_DEBUG,"---> DUNNO <--- !!! resetting message buffers!");
+ prevlen = 0;
+ prevbuf[0] = 0x0;
+ cflag = 1;
+ continue;
+ }
+ /*
+ printf( "POST-Parse: %d -> ",len);
+ for (i=0; i<len; i++)
+ printf( "0x%02X ",prevbuf[i]);
+ printf( "\n");
+ */
+
+ //TODO: Checksum calculation / check of russound-message
+ parseRussMsg(buf,len);
+ //} //end while worked
+ if (cflag)
continue;
- } else if (prevlen > 0 && prevbuf[0] == 0xF0 && buf[len-1] == 0xF7) { // message complete
- printf("..complete..%d %d\n",prevlen,len);
- memcpy(prevbuf+prevlen,buf,len);
- len += prevlen;
- prevlen = 0;
- memcpy(buf,prevbuf,len);
- } else if (prevlen > 0 && prevbuf[0] == 0xF0) { //continuation message
- printf("..continue..%d %d\n",prevlen,len);
- memcpy(prevbuf+prevlen,buf,len);
- prevlen += len;
- continue;
- } else { //DUNNO!!
- syslog(LOG_DEBUG,"---> DUNNO <--- !!! resetting message buffers!");
- prevlen = 0;
- prevbuf[0] = 0x0;
- continue;
- }
- //DEBUG
- printf( "POST-Parse: %d -> ",len);
- for (i=0; i<len; i++)
- printf( "0x%02X ",prevbuf[i]);
- printf( "\n");
- //END DEBUG code
-
- //TODO: Checksum calculation / check of russound-message
- if ((len==34) && (buf[0]==0xF0) && (buf[9]==0x04)) { //zone-status
- syslog(LOG_DEBUG,"russ Controller:%d Zone:%d Status:%d src:%d vol:%d bass:%d treb:%d loud:%d bal:%d sys:%d shrsrc:%d party:%d,DnD:%d\n",
- buf[4],buf[12],buf[20],buf[21],buf[22],buf[23],buf[24],buf[25],buf[26],buf[27],buf[28],buf[29],buf[30]);
- buf[12] = (buf[4]*ZONES_PER_CONTROLLER)+buf[12]; //controller + zonenumber
- if (buf[20] != zones[buf[12]].zonepower)
- updateZone(buf[12],buf[20],1);
- if (buf[21] != zones[buf[12]].srcid)
- updateZone(buf[12],buf[21],2);
- if (buf[22] != zones[buf[12]].volume)
- updateZone(buf[12],buf[22],3);
- if (buf[23] != zones[buf[12]].bass)
- updateZone(buf[12],buf[23],4);
- if (buf[24] != zones[buf[12]].treble)
- updateZone(buf[12],buf[24],5);
- if (buf[25] != zones[buf[12]].loudness)
- updateZone(buf[12],buf[25],6);
- if (buf[26] != zones[buf[12]].balance)
- updateZone(buf[12],buf[26],7);
- if (buf[29] != zones[buf[12]].partymode)
- updateZone(buf[12],buf[29],8);
- if (buf[30] != zones[buf[12]].dnd)
- updateZone(buf[12],buf[30],9);
- zones[buf[12]].inited = 1;
- } else if ((len==24) && (buf[0]==0xF0) && (buf[9]==0x05) && (buf[13]==0x00)) { //zone turn-on volume
- //FIXME: this *might* be wrong andf trigger also on other msgs, as it's written otherwise in the docs, the checked bytes are just a guess!
- syslog(LOG_DEBUG,"russ Controller:%d Zone:%d TurnOnVolume:%d",
- buf[4],buf[12],buf[21]);
- buf[12] = (buf[4]*ZONES_PER_CONTROLLER)+buf[12]; //controller + zonenumber
- if (buf[21] != zones[buf[12]].onvolume)
- updateZone(buf[12],buf[21],10);
- } else {
- //FIXME: just for debugging
- for (i=0; i<len; i++)
- printf("%d:0x%02X ",i,buf[i]);
- printf(" unknown len: %d\n",len);
- for (i=0; i<len; i++)
- printf("0x%02X ",buf[i]);
- printf("\n");
- }
- }
+ } //end with recvfrom
syslog(LOG_WARNING,"russ: closed socket"); //break in read-loop
pthread_exit(NULL);
-}
+} //end func russhandler
eibaddr_t readgaddr (const char *addr) {
int a, b, c;
@@ -682,11 +740,14 @@
char *p;
char pidstr[255];
- while ((c = getopt (argc, argv, "dp:i:l:a:z:u:")) != -1)
+ while ((c = getopt (argc, argv, "dp:i:l:a:z:u:s")) != -1)
switch (c) {
case 'd':
daemonize = 1;
break;
+ case 's':
+ sendOnStart = 1;
+ break;
case 'p':
pidfilename = optarg;
break;
@@ -782,6 +843,7 @@
// PTHREAD_CREATE_DETACHED?
knxthread = pthread_create(&threads[1], NULL, knxhandler, NULL); //id, thread attributes, subroutine, arguments
russthread = pthread_create(&threads[2], NULL, russhandler, NULL); //id, thread attributes, subroutine, arguments
+ syslog(LOG_DEBUG,"Threads created: %d %d",knxthread,russthread);
//TODO: Maybe another console/TCP-server/Logging thread?
while (1) {
syslog(LOG_DEBUG, "%s daemon running", DAEMON_NAME);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|