From aeea6033a8c023743539d4335d04cb24c2b9bfa9 Mon Sep 17 00:00:00 2001 From: painseeker <> Date: Tue, 19 Jan 2010 19:33:01 +0000 Subject: [PATCH] Multiple SIS_PM units now work. (After fixing sispmctl-bug, see commandref.html.) NOTE: Changing the order of the units on the USB while fhem.pl is running WILL STILL BREAK THINGS! git-svn-id: https://svn.fhem.de/fhem/trunk@551 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/70_SISPM.pm | 75 +++++++++++++++++++++++++++++---------- fhem/docs/commandref.html | 53 +++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 25 deletions(-) diff --git a/fhem/FHEM/70_SISPM.pm b/fhem/FHEM/70_SISPM.pm index 9c96a3855..c0fad1698 100644 --- a/fhem/FHEM/70_SISPM.pm +++ b/fhem/FHEM/70_SISPM.pm @@ -29,7 +29,7 @@ # # Contributed by Kai 'wusel' Siering in 2010 # Based in part on work for FHEM by other authors ... -# $Id: 70_SISPM.pm,v 1.2 2010-01-18 01:12:34 painseeker Exp $ +# $Id: 70_SISPM.pm,v 1.3 2010-01-19 19:33:01 painseeker Exp $ ########################### package main; @@ -102,6 +102,7 @@ SISPM_Define($$) if(!$FH) { return "SISPM Can't start $dev: $!"; } + $hash->{NUMUNITS}=0; local $_; while (<$FH>) { if(/^(No GEMBIRD SiS-PM found.)/) { @@ -111,9 +112,11 @@ SISPM_Define($$) if(/^Gembird #(\d+) is USB device (\d+)./) { Log 3, "SISPM found SISPM device number $1 as USB $2"; $hash->{UNITS}{$1}{USB}=$2; - $currentdevice=$numdetected; + $currentdevice=$1; $numdetected++; + $hash->{NUMUNITS}=$numdetected; } + if(/^This device has a serial number of (.*)/) { my $serial=$1; Log 3, "SISPM device number " . $currentdevice . " has serial $serial"; @@ -179,13 +182,19 @@ SISPM_GetStatus($) my $name = $hash->{NAME}; my $dev = $hash->{DeviceName}; my $FH; + my $i; # Call us in n seconds again. # InternalTimer(gettimeofday()+ $hash->{Timer}, "SISPM_GetStatus", $hash, 1); Log 4, "SISPM contacting device"; - my $tmpdev=sprintf("%s -s -g all 2>&1 |", $dev); + my $tmpdev=sprintf("%s -s ", $dev); + + for($i=0; $i<$hash->{NUMUNITS}; $i++) { + $tmpdev=sprintf("%s -d %d -g all ", $tmpdev, $i); + } + $tmpdev=sprintf("%s 2>&1 |", $tmpdev); open($FH, $tmpdev); if(!$FH) { return "SISPM Can't open pipe: $dev: $!"; @@ -232,6 +241,10 @@ SISPM_Read($) my $reading; my $readingforstatus; my $currentserial="none"; + my $currentdevice=0; + my $currentusbid=0; + my $renumbered=0; + my $newPMfound=0; ($eof, @lines) = nonblockGetLinesSISPM($FH); @@ -255,39 +268,65 @@ SISPM_Read($) next; } +# wusel, 2010-01-19: Multiple (2) SIS PM do work now. But USB renumbering will still +# break things rather badly. Thinking about dropping it altogether, +# that is wipe old state data ($hash->{UNITS} et. al.) and rebuild +# data each time from scratch. That should work as SIS_PMS uses the +# serial as key; unfortunately, sispmctl doesn't offer this (and it +# wont work due to those FFFFFFxx readings), so we need to keep +# track of unit number <-> serial ... But if between reading this +# data and a "set" statement something changes, we still could switch +# the wrong socket. +# +# As sispmctl 2.7 is broken already for multiple invocations with -d, +# I consider fixing both the serial number issue as well as add the +# serial as selector ... Drat. Instead of getting the ToDo list shorter, +# it just got longer ;-) + if($inputline =~ /^(No GEMBIRD SiS-PM found.)/) { - Log 3, "SISPM woops? $1"; + Log 3, "SISPM Whoopsie? $1"; + next; } if($inputline =~ /^Gembird #(\d+) is USB device (\d+)\./ || $inputline =~ /^Accessing Gembird #(\d+) USB device (\d+)/) { Log 5, "SISPM found SISPM device number $1 as USB $2"; - if($hash->{UNITS}{$1}{USB}!=$2) { -# -wusel, 2010-01-15: FIXME! Verify that this IS the device we're -# looking for. As USB renumbering can happen, -# if the $hash->{UNITS}{$1}{USB}=$2 not matches -# we'd need to redo a "sispmctl -s", maybe by -# going to SISPM_Define() again? -# -# Hoping the best for now -- DON'T TOUCH RUNNING -# BOX WITH MORE THAN ONE SISPM CONNECTED OR HELL -# MAY BREAK LOOSE ;) - Log 3, "SISPM: Odd, got unit $1 as USB $2, have $1 on file as " . $hash->{UNITS}{$1}{USB} . "?"; + if($1 < $hash->{NUMUNITS}) { + if($hash->{UNITS}{$1}{USB}!=$2) { + Log 3, "SISPM: USB ids changed (unit $1 is now USB $2 but was " . $hash->{UNITS}{$1}{USB} . "); will fix."; + $renumbered=1; + } + } else { # Something wonderful has happened, we have a new SIS PM! + Log 3, "SISPM: Wuuuhn! Found a new unit $1 as USB $2. Will assimilate it."; + $newPMfound=1; + } + $currentdevice=$1; + $currentusbid=$2; + $currentserial="none"; + if(defined($hash->{UNITS}{$currentdevice}{SERIAL})) { + $currentserial=$hash->{UNITS}{$currentdevice}{SERIAL}; } } -# -wusel, 2010-01-15: FIXME! This will break on >1 PMS! if($inputline =~ /^This device has a serial number of (.*)/) { $currentserial=FixSISPMSerial($1); if($currentserial eq "00:00:00:00:00") { Log 3, "SISPM Whooopsie! Your serial nullified ($currentserial). Skipping ..."; next; } + + if($newPMfound==1) { + $hash->{UNITS}{$currentdevice}{USB}=$currentusbid; + $hash->{UNITS}{$currentdevice}{SERIAL}=$currentserial; + $hash->{SERIALS}{$currentserial}{UNIT}=$currentdevice; + $hash->{SERIALS}{$currentserial}{USB}=$currentusbid; + $hash->{NUMUNITS}+=1; + } } if($inputline =~ /^Status of outlet (\d):\s+(.*)/) { if($currentserial ne "none") { - Log 5, "SISPM found socket $1 on $currentserial, state $2"; + Log 3, "SISPM found socket $1 on $currentserial, state $2"; my $dmsg="socket " . $currentserial . " $1 state " . $2; my %addvals; Dispatch($hash, $dmsg, \%addvals); @@ -332,7 +371,7 @@ sub SISPM_Write($$$) { } if(defined($hash->{SERIALS}{$serial}{UNIT})) { - $deviceno=($hash->{SERIALS}{$serial}{UNIT})+1; + $deviceno=($hash->{SERIALS}{$serial}{UNIT}); $cmdline=sprintf("%s -d %d -%s %d 2>&1 >/dev/null", $dev, $deviceno, $cmdletter, $socket); system($cmdline); } else { diff --git a/fhem/docs/commandref.html b/fhem/docs/commandref.html index f19dc22b5..c26e26dd3 100644 --- a/fhem/docs/commandref.html +++ b/fhem/docs/commandref.html @@ -3467,13 +3467,52 @@ Forecast Cloudy define <name> SISPM </path/to/sispmctl>

- PLEASE NOTE: This module is to be considered alpha quality; it has not been - tested extensively, especially the interaction between "set" commands and the sheduled - status reading needs more obervation. (Testing with FIFOs seems as if it's working - without blocking nor interference, but that's on a mostly unloaded, fast system.)

- BE CAREFUL when using multiple PMs on one host; the parser in SISPM_Define() is MOST - PROBABLY broken here, I haven't had the opportunity to test this yet. YOU HAVE BEEN - WARNED.
And now to what's this disclaimer tries to prevent you from using ;)

+
+ PLEASE NOTE: This module is still work in progess; please treat it as such. + (That is, don't but your central heating on SISPM in a cold winter just yet ;))

+ Further tests should be done regarding the interaction between "set" commands and the sheduled + status reading. (Testing with FIFOs seems as if it's working without blocking nor interference, + but that's on a mostly unloaded, fast system.)

+ When using multiple SIS PMs on one host, sispmctl up to and including V 2.7 has a bug: +
plug-2:# sispmctl -v -s -d 1 -g all -d 2 -g all
+
+SiS PM Control for Linux 2.7
+
+(C) 2004, 2005, 2006, 2007, 2008 by Mondrian Nuessle, (C) 2005, 2006 by Andreas Neuper.
+This program is free software.
+[...]
+
+Gembird #0 is USB device 013.This device is a 4-socket SiS-PM.
+[...]
+
+Gembird #1 is USB device 015.This device is a 4-socket SiS-PM.
+[...]
+
+Accessing Gembird #1 USB device 015
+Status of outlet 1:     on
+Status of outlet 2:     on
+Status of outlet 3:     on
+Status of outlet 4:     on
+Error performing requested action
+Libusb error string: error sending control message: Invalid argument
+Terminating
+*** glibc detected *** sispmctl: double free or corruption (fasttop): 0x000251e0 ***
+[...]
+ Well, the fix is simple and will be sent upstream, but in case it's not incorporated + at the time you need it, here it is; it's easy to apply even by hand ;-) +
+--- src/main.c-old      2010-01-19 16:56:15.000000000 +0100
++++ src/main.c  2010-01-19 16:54:56.000000000 +0100
+@@ -441,7 +441,7 @@
+            }
+            break;
+        case 'd': // replace previous (first is default) device by selected one
+-           if(udev!=NULL) usb_close (udev);
++           if(udev!=NULL) { usb_close (udev); udev=NULL; }
+            devnum = atoi(optarg);
+            if(devnum>=count) devnum=count-1;
+            break;
+

Defines a path to the program "sispmctl", which is used to control (locally attached) "Silver Shield Power Manager" devices. Usually these are connected to the local computer