diff --git a/fhem/CHANGED b/fhem/CHANGED index 39b14d491..710595b82 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,25 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - featire: SD_ProtocolData.pm v1.1.7 + new protocol 97 Momento remote control for wireless digital picture frame + new protocol 58 Weather F007-T + new protocol 27 for EuroChron EFTH-800 + new protocol 26 - Remote control xavax 00111939 + new protocol 20 - Remote control diesel heating + - feature: 00_SIGNALduino.pm version 3.4.2 + automatic load cc1101 config after change value or restart + made multiple get commands more easy and robust to handle + extended cc1101 settings to ccconf reading +- bugfix: 00_SIGNALduino.pm version 3.4.2 + several retrys to initialize the SIGNALduino + flash via http: Fixed Filename extraction of URL + bug fixed set sduino cc1101_rAmpl 42 + Allow lower case letters for hex values ​​in set / get cc1101_reg +- change: + filtered possible set/get commands per device type + added meta information to 00_SIGNALduino.pm + patable list values adapted to values allowed per frequency + ranges - new: 70_HYDRAWISE: New module for controlling Hunter Hydrawise irrigation - feature: 93_Log2Syslog: support time-secfrac of RFC 3339, minor fix - feature: 93_Log2Syslog: new attribute 'timeSpec', send and parse messages diff --git a/fhem/FHEM/00_SIGNALduino.pm b/fhem/FHEM/00_SIGNALduino.pm index dde23c091..b19d8d82e 100644 --- a/fhem/FHEM/00_SIGNALduino.pm +++ b/fhem/FHEM/00_SIGNALduino.pm @@ -1,14 +1,15 @@ # $Id$ # -# v3.4.1 +# v3.4.2 - https://github.com/RFD-FHEM/RFFHEM/tree/dev-r34 # The module is inspired by the FHEMduino project and modified in serval ways for processing the incoming messages # see http://www.fhemwiki.de/wiki/SIGNALDuino # It was modified also to provide support for raw message handling which can be send from the SIGNALduino # The purpos is to use it as addition to the SIGNALduino which runs on an arduno nano or arduino uno. # It routes Messages serval Modules which are already integrated in FHEM. But there are also modules which comes with it. +# # N. Butzek, S. Butzek, 2014-2015 # S.Butzek,Ralf9 2016-2019 - +# S.Butzek, HomeAutoUser, elektron-bbs 2019-2020 package main; my $missingModulSIGNALduino=""; @@ -31,7 +32,7 @@ use lib::SD_Protocols; use constant { - SDUINO_VERSION => "v3.4.1", + SDUINO_VERSION => "v3.4.2", SDUINO_INIT_WAIT_XQ => 1.5, # wait disable device SDUINO_INIT_WAIT => 2, SDUINO_INIT_MAXRETRY => 3, @@ -40,11 +41,12 @@ use constant { SDUINO_KEEPALIVE_MAXRETRY => 3, SDUINO_WRITEQUEUE_NEXT => 0.3, SDUINO_WRITEQUEUE_TIMEOUT => 2, - + SDUINO_DISPATCH_VERBOSE => 5, # default 5 SDUINO_MC_DISPATCH_VERBOSE => 5, # wenn kleiner 5, z.B. 3 dann wird vor dem dispatch mit loglevel 3 die ID und rmsg ausgegeben SDUINO_MC_DISPATCH_LOG_ID => '12.1', # die o.g. Ausgabe erfolgt nur wenn der Wert mit der ID uebereinstimmt - SDUINO_PARSE_DEFAULT_LENGHT_MIN => 8 + SDUINO_PARSE_DEFAULT_LENGHT_MIN => 8, + SDUINO_GET_CONFIGQUERY_DELAY => 0.75 # delay for cmd to no overwrite a working cmd }; @@ -65,88 +67,29 @@ sub SIGNALduino_Log3($$$); our %modules; our %defs; -# Two options are possible to specify a get command -# Option 1 will send a serial command to the uC and wait for response. For this an array needs to be specified -# Option 2 will call a anonymous sub which does some things -my %gets = ( # Name, Data to send to the SIGNALduino, Regexp for the answer - "version" => ["V", 'V\s.*SIGNAL(duino|ESP).*'], - "freeram" => ["R", '^[0-9]+'], -# "raw" => ["", '.*'], - "uptime" => ["t", '^[0-9]+' ], - "cmds" => ["?", '.*Use one of[ 0-9A-Za-z]+[\r\n]*$' ], -# "ITParms" => ["ip",'.*'], - "ping" => ["P",'^OK$'], - "config" => ["CG",'^MS.*MU.*MC.*'], -# "protocolIDs" => ["none",'none'], - "ccconf" => ["C0DnF", 'C0Dn11.*'], - "ccreg" => ["C", '^C.* = .*'], - "ccpatable" => ["C3E", '^C3E = .*'], -# "ITClock" => ["ic", '\d+'], -# "FAParms" => ["fp", '.*' ], -# "TCParms" => ["dp", '.*' ], -# "HXParms" => ["hp", '.*' ] -# "availableFirmware" => ["none",'none'], - "availableFirmware" => sub { - my ($hash, @a) = @_; - - if ($missingModulSIGNALduino =~ m/JSON/ ) - { - $hash->{logMethod}->($hash->{NAME}, 1, "$hash->{NAME}: get $a[1] failed. Pleas install Perl module JSON. Example: sudo apt-get install libjson-perl"); - return "$a[1]: \n\nFetching from github is not possible. Please install JSON. Example:
sudo apt-get install libjson-perl"; - } - - my $channel=AttrVal($hash->{NAME},"updateChannelFW","stable"); - my $hardware=AttrVal($hash->{NAME},"hardware",undef); - - my ($validHw) = $modules{$hash->{TYPE}}{AttrList} =~ /.*hardware:(.*?)\s/; - $hash->{logMethod}->($hash->{NAME}, 1, "$hash->{NAME}: found availableFirmware for $validHw"); - - if (!defined($hardware) || $validHw !~ /$hardware(?:,|$)/ ) - { - $hash->{logMethod}->($hash->{NAME}, 1, "$hash->{NAME}: get $a[1] failed. Please set attribute hardware first"); - return "$a[1]: \n\n$hash->{NAME}: get $a[1] failed. Please choose one of $validHw attribute hardware"; - } - SIGNALduino_querygithubreleases($hash); - return "$a[1]: \n\nFetching $channel firmware versions for $hardware from github\n"; - }, - "raw" => sub { - my ($hash, @a) = @_; - if ($a[2] =~ /^M[CcSU];.*/) - { - $a[2]="\002$a[2]\003"; ## Add start end end marker if not already there - $hash->{logMethod}->($hash->{NAME}, 5, "$hash->{NAME}: msg adding start and endmarker to message"); - } - if ($a[2] =~ /\002M.;.*;\003$/) - { - $hash->{logMethod}->( $hash->{NAME}, 4, "$hash->{NAME}: msg get raw: $a[2]"); - return SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $a[2]); - } - }, - +my %gets = ( # NameOFCommand => StyleMod for Fhemweb, SubToCall if get is executed, String to send to uC, sub called with response, regex to verify response, + "?" => ['', \&SIGNALduino_Get_FhemWebList ], + "version" => ['noArg', \&SIGNALduino_Get_Command, "V", \&SIGNALduino_CheckVersionResp, 'V\s.*SIGNAL(?:duino|ESP).*(?:\s\d\d:\d\d:\d\d)' ], + "freeram" => ['noArg', \&SIGNALduino_Get_Command, "R", \&SIGNALduino_GetResponseUpdateReading, '^[0-9]+' ] , + "uptime" => ['noArg', \&SIGNALduino_Get_Command, "t", \&SIGNALduino_CheckUptimeResponse, '^[0-9]+' ], + "cmds" => ['noArg', \&SIGNALduino_Get_Command, "?", \&SIGNALduino_CheckCmdsResponse, '.*' ], + "ping" => ['noArg', \&SIGNALduino_Get_Command, "P", \&SIGNALduino_GetResponseUpdateReading, '^OK$' ], + "config" => ['noArg', \&SIGNALduino_Get_Command, "CG", \&SIGNALduino_GetResponseUpdateReading, '^MS.*MU.*MC.*' ], + "ccconf" => ['noArg', \&SIGNALduino_Get_Command, "C0DnF", \&SIGNALduino_CheckccConfResponse, 'C0Dn11=[A-F0-9a-f]+'], + "ccreg" => ['textFieldNL', \&SIGNALduino_Get_Command_CCReg,"C", \&SIGNALduino_CheckCcregResponse, '^(?:C[A-Fa-f0-9]{2}\s=\s[0-9A-Fa-f]+$|ccreg 00:)'], + "ccpatable" => ['noArg', \&SIGNALduino_Get_Command, "C3E", \&SIGNALduino_CheckccPatableResponse, '^C3E\s=\s.*'], + "raw" => ['textFieldNL', \&SIGNALduino_Get_Raw ], + "availableFirmware" => ['noArg', \&SIGNALduino_Get_availableFirmware ] ); -my %sets = ( - "raw" => '', - "flash" => '', - "reset" => 'noArg', - "close" => 'noArg', - #"disablereceiver" => "", - #"ITClock" => 'slider,100,20,700', - "enableMessagetype" => 'syncedMS,unsyncedMU,manchesterMC', - "disableMessagetype" => 'syncedMS,unsyncedMU,manchesterMC', - "sendMsg" => "", - "cc1101_freq" => '', - "cc1101_bWidth" => '58,68,81,102,116,135,162,203,232,270,325,406,464,541,650,812', - "cc1101_rAmpl" => '24,27,30,33,36,38,40,42', - "cc1101_sens" => '4,8,12,16', - "cc1101_patable_433" => '-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm', - "cc1101_patable_868" => '-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm', -); - +my %ProtocolListSIGNALduino; my %patable = ( "433" => { + "-30_dBm" => '12', + "-20_dBm" => '0E', + "-15_dBm" => '1D', "-10_dBm" => '34', "-5_dBm" => '68', "0_dBm" => '60', @@ -156,6 +99,9 @@ my %patable = ( }, "868" => { + "-30_dBm" => '03', + "-20_dBm" => '0F', + "-15_dBm" => '1E', "-10_dBm" => '27', "-5_dBm" => '67', "0_dBm" => '50', @@ -164,9 +110,80 @@ my %patable = ( "10_dBm" => 'C2', }, ); +my @ampllist = (24, 27, 30, 33, 36, 38, 40, 42); # rAmpl(dB) +my %sets = ( + #Command name [FhemWeb Argument type, code to run] + "?" => ['', \&SIGNALduino_Set_FhemWebList ], + "raw" => ['textFieldNL',\&SIGNALduino_Set_raw ], + "flash" => ['textFieldNL', \&SIGNALduino_Set_flash ], + "reset" => ['noArg', \&SIGNALduino_Set_reset ], + "close" => ['noArg', \&SIGNALduino_Set_close ], + "enableMessagetype" => ['syncedMS,unsyncedMU,manchesterMC', \&SIGNALduino_Set_MessageType ], + "disableMessagetype" => ['syncedMS,unsyncedMU,manchesterMC', \&SIGNALduino_Set_MessageType ], + "sendMsg" => ['textFieldNL',\&SIGNALduino_Set_sendMsg ], + "cc1101_freq" => ['textFieldNL', \&cc1101::SetFreq ], + "cc1101_bWidth" => ['58,68,81,102,116,135,162,203,232,270,325,406,464,541,650,812', \&SIGNALduino_Set_bWidth ], + "cc1101_rAmpl" => ['24,27,30,33,36,38,40,42', \&cc1101::setrAmpl ], + "cc1101_sens" => ['4,8,12,16', \&cc1101::SetSens ], + "cc1101_patable" => ['-30_dBm,-20_dBm,-15_dBm,-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm', \&cc1101::SetPatable ], + "cc1101_reg" => [ 'textFieldNL', \&cc1101::SetRegisters ], +); -my @ampllist = (24, 27, 30, 33, 36, 38, 40, 42); # rAmpl(dB) +## Supported config CC1101 ## +my @modformat = ("2-FSK","GFSK","-","ASK/OOK","4-FSK","-","-","MSK"); +my @syncmod = ("No preamble/sync","15/16 sync word bits detected","16/16 sync word bits detected","30/32 sync word bits detected", + "No preamble/sync, carrier-sense above threshold, carrier-sense above threshold", "15/16 + carrier-sense above threshold", "16/16 + carrier-sense above threshold", "30/32 + carrier-sense above threshold"); + +my %cc1101_register = ( # for get ccreg 99 and set cc1101_reg + "00" => 'IOCFG2 ', # ! the values with spaces for output get ccreg 99 ! + "01" => 'IOCFG1 ', + "02" => 'IOCFG0 ', + "03" => 'FIFOTHR ', + "04" => 'SYNC1 ', + "05" => 'SYNC0 ', + "06" => 'PKTLEN ', + "07" => 'PKTCTRL1', + "08" => 'PKTCTRL0', + "09" => 'ADDR ', + "0A" => 'CHANNR ', + "0B" => 'FSCTRL1 ', + "0C" => 'FSCTRL0 ', + "0D" => 'FREQ2 ', + "0E" => 'FREQ1 ', + "0F" => 'FREQ0 ', + "10" => 'MDMCFG4 ', + "11" => 'MDMCFG3 ', + "12" => 'MDMCFG2 ', + "13" => 'MDMCFG1 ', + "14" => 'MDMCFG0 ', + "15" => 'DEVIATN ', + "16" => 'MCSM2 ', + "17" => 'MCSM1 ', + "18" => 'MCSM0 ', + "19" => 'FOCCFG ', + "1A" => 'BSCFG ', + "1B" => 'AGCCTRL2', + "1C" => 'AGCCTRL1', + "1D" => 'AGCCTRL0', + "1E" => 'WOREVT1 ', + "1F" => 'WOREVT0 ', + "20" => 'WORCTRL ', + "21" => 'FREND1 ', + "22" => 'FREND0 ', + "23" => 'FSCAL3 ', + "24" => 'FSCAL2 ', + "25" => 'FSCAL1 ', + "26" => 'FSCAL0 ', + "27" => 'RCCTRL1 ', + "28" => 'RCCTRL0 ', + "29" => 'FSTEST ', + "2A" => 'PTEST ', + "2B" => 'AGCTEST ', + "2C" => 'TEST2 ', + "2D" => 'TEST1 ', + "2E" => 'TEST0 ', +); ## Supported Clients per default my $clientsSIGNALduino = ":IT:" @@ -198,8 +215,9 @@ my $clientsSIGNALduino = ":IT:" ."CUL_EM:" ."Fernotron:" ."SD_Keeloq:" + ."SD_GT:" ."SIGNALduino_un:" - ; + ; ## default regex match List for dispatching message to logical modules, can be updated during runtime because it is referenced my %matchListSIGNALduino = ( @@ -218,24 +236,24 @@ my %matchListSIGNALduino = ( "14:Dooya" => '^P16#[A-Fa-f0-9]+', "15:SOMFY" => '^Ys[0-9A-F]+', "16:SD_WS_Maverick" => '^P47#[A-Fa-f0-9]+', - "17:SD_UT" => '^P(?:14|29|30|34|46|68|69|76|81|83|86|90|91|91.1|92|93|95)#.*', # universal - more devices with different protocols + "17:SD_UT" => '^P(?:14|20|26|29|30|34|46|68|69|76|81|83|86|90|91|91.1|92|93|95|97)#.*', # universal - more devices with different protocols "18:FLAMINGO" => '^P13\.?1?#[A-Fa-f0-9]+', # Flamingo Smoke "19:CUL_WS" => '^K[A-Fa-f0-9]{5,}', "20:Revolt" => '^r[A-Fa-f0-9]{22}', "21:FS10" => '^P61#[A-F0-9]+', "22:Siro" => '^P72#[A-Fa-f0-9]+', "23:FHT" => "^81..(04|09|0d)..(0909a001|83098301|c409c401)..", - "24:FS20" => "^81..(04|0c)..0101a001", - "25:CUL_EM" => "^E0.................", + "24:FS20" => "^81..(04|0c)..0101a001", + "25:CUL_EM" => "^E0.................", "26:Fernotron" => '^P82#.*', "27:SD_BELL" => '^P(?:15|32|41|42|57|79|96)#.*', "28:SD_Keeloq" => '^P(?:87|88)#.*', + "29:SD_GT" => '^P49#[A-Fa-f0-9]+', "X:SIGNALduino_un" => '^[u]\d+#.*', ); -my %ProtocolListSIGNALduino; my %symbol_map = (one => 1 , zero =>0 ,sync => '', float=> 'F', 'start' => ''); @@ -262,7 +280,7 @@ sub SIGNALduino_Initialize($) { $hash->{GetFn} = "SIGNALduino_Get"; $hash->{SetFn} = "SIGNALduino_Set"; $hash->{AttrFn} = "SIGNALduino_Attr"; - $hash->{AttrList} = + $hash->{AttrList} = "Clients MatchList do_not_notify:1,0 dummy:1,0" ." hexFile" ." initCommands" @@ -289,14 +307,14 @@ sub SIGNALduino_Initialize($) { $hash->{ShutdownFn} = "SIGNALduino_Shutdown"; $hash->{FW_detailFn} = "SIGNALduino_FW_Detail"; $hash->{FW_deviceOverview} = 1; - + $hash->{msIdList} = (); $hash->{muIdList} = (); $hash->{mcIdList} = (); - + #our $attr; - + %ProtocolListSIGNALduino = SIGNALduino_LoadProtocolHash("$attr{global}{modpath}/FHEM/lib/SD_ProtocolData.pm"); if (exists($ProtocolListSIGNALduino{error}) ) { @@ -309,7 +327,7 @@ sub SIGNALduino_Initialize($) { # Predeclare Variables from other modules may be loaded later from fhem # our $FW_wname; -our $FW_ME; +our $FW_ME; # # Predeclare Variables from other modules may be loaded later from fhem @@ -322,8 +340,8 @@ our $FW_detail; # # returns a hash with protocols if loaded without error. Returns a hash with {eror} => errormessage if there was an error -##################################### -sub SIGNALduino_LoadProtocolHash($) { +##################################### +sub SIGNALduino_LoadProtocolHash($) { my $ret= lib::SD_Protocols::LoadHash($_[0]); return %$ret; } @@ -348,51 +366,51 @@ sub SIGNALduino_Define($$) { Log3 undef, 2, $msg; return $msg; } - + DevIo_CloseDev($hash); my $name = $a[0]; - + if (!exists &round) { Log3 $name, 1, "$name: Define, Signalduino can't be activated (sub round not found). Please update Fhem via update command"; return undef; } - + my $dev = $a[2]; #Debug "dev: $dev" if ($debug); #my $hardware=AttrVal($name,"hardware","nano"); #Debug "hardware: $hardware" if ($debug); - - + + if($dev eq "none") { Log3 $name, 1, "$name: Define, device is none, commands will be echoed only"; $attr{$name}{dummy} = 1; #return undef; } - + if ($dev ne "none" && $dev =~ m/[a-zA-Z]/ && $dev !~ m/\@/) { # bei einer IP wird kein \@57600 angehaengt $dev .= "\@57600"; - } - + } + #$hash->{CMDS} = ""; $hash->{Clients} = $clientsSIGNALduino; $hash->{MatchList} = \%matchListSIGNALduino; $hash->{DeviceName} = $dev; - $hash->{logMethod} = \&main::Log3; - + $hash->{logMethod} = \&main::Log3; + my $ret=undef; - + InternalTimer(gettimeofday(), 'SIGNALduino_IdList',"sduino_IdList:$name",0); # verzoegern bis alle Attribute eingelesen sind - + if($dev ne "none") { $ret = DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect'); } else { $hash->{DevState} = 'initialized'; readingsSingleUpdate($hash, "state", "opened", 1); } - + $hash->{DMSG}="nothing"; $hash->{LASTDMSG} = "nothing"; $hash->{LASTDMSGID} = "nothing"; @@ -402,7 +420,7 @@ sub SIGNALduino_Define($$) { #notifyRegexpChanged($hash,"^$name$:^opened\$"); # Auf das Event opened der eigenen Definition reagieren #notifyRegexpChanged($hash,"sduino:opened"); # Auf das Event opened der eigenen Definition reagieren #$hash->{NOTIFYDEV}="$name"; - Log3 $name, 3, "$name: Define, Firmwareversion: ".$hash->{READINGS}{version}{VAL} if ($hash->{READINGS}{version}{VAL}); + #Log3 $name, 3, "$name: Define, Firmwareversion: ".$hash->{READINGS}{version}{VAL} if ($hash->{READINGS}{version}{VAL}); return $ret; } @@ -422,7 +440,7 @@ sub SIGNALduino_Connect($$) { sub SIGNALduino_Undef($$) { my ($hash, $arg) = @_; my $name = $hash->{NAME}; - + foreach my $d (sort keys %defs) { if(defined($defs{$d}) && defined($defs{$d}{IODev}) && @@ -435,9 +453,9 @@ sub SIGNALduino_Undef($$) { } SIGNALduino_Shutdown($hash); - - DevIo_CloseDev($hash); - RemoveInternalTimer($hash); + + DevIo_CloseDev($hash); + RemoveInternalTimer($hash); return undef; } @@ -450,16 +468,16 @@ sub SIGNALduino_Shutdown($) { } ############################### -sub SIGNALduino_flash($) { +sub SIGNALduino_avrdude($) { my $name = shift; my $hash = $defs{$name}; - + if (defined($hash->{helper}{stty_pid})) { waitpid( $hash->{helper}{stty_pid}, 0 ); delete ( $hash->{helper}{stty_pid}); } - + readingsSingleUpdate($hash,"state","FIRMWARE UPDATE running",1); $hash->{helper}{avrdudelogs} .= "$name closed\n"; my $logFile = AttrVal("global", "logdir", "./log/") . "$hash->{TYPE}-Flash.log"; @@ -478,14 +496,14 @@ sub SIGNALduino_flash($) { if ($? != 0 ) { readingsSingleUpdate($hash,"state","FIRMWARE UPDATE with error",1); # processed in tests - $hash->{logMethod}->($name ,3, "$name: flash, ERROR: avrdude exited with error $?"); + $hash->{logMethod}->($name ,3, "$name: avrdude, ERROR: avrdude exited with error $?"); FW_directNotify("FILTER=$name", "#FHEMWEB:WEB", "FW_okDialog('ERROR: avrdude exited with error, for details see last flashlog.')", ""); $hash->{FLASH_RESULT}="ERROR: avrdude exited with error"; # processed in tests } else { - $hash->{logMethod}->($name ,3, "$name: flash, Firmware update was successfull"); + $hash->{logMethod}->($name ,3, "$name: avrdude, Firmware update was successfull"); readingsSingleUpdate($hash,"state","FIRMWARE UPDATE successfull",1); # processed in tests } - + local $/=undef; if (-e $logFile) { open FILE, $logFile; @@ -498,257 +516,212 @@ sub SIGNALduino_flash($) { readingsSingleUpdate($hash,"state","FIRMWARE UPDATE with error",1); $hash->{FLASH_RESULT}= "WARNING: avrdude created no log file"; # processed in tests } - + DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect'); $hash->{helper}{avrdudelogs} .= "$name reopen started\n"; return $hash->{FLASH_RESULT}; } +############################### +sub SIGNALduino_PrepareFlash { + my ($hash,$hexFile) = @_; + + my $name=$hash->{NAME}; + my $hardware=AttrVal($name,"hardware",""); + my ($port,undef) = split('@', $hash->{DeviceName}); + my $baudrate= 57600; + my $log = ""; + my $avrdudefound=0; + my $tool_name = "avrdude"; + my $path_separator = ':'; + if ($^O eq 'MSWin32') { + $tool_name .= ".exe"; + $path_separator = ';'; + } + for my $path ( split /$path_separator/, $ENV{PATH} ) { + if ( -f "$path/$tool_name" && -x _ ) { + $avrdudefound=1; + last; + } + } + $hash->{logMethod}->($name, 5, "$name: PrepareFlash, avrdude found = $avrdudefound"); + return "avrdude is not installed. Please provide avrdude tool example: sudo apt-get install avrdude" if($avrdudefound == 0); + + $log .= "flashing Arduino $name\n"; + $log .= "hex file: $hexFile\n"; + $log .= "port: $port\n"; + + # prepare default Flashcommand + my $defaultflashCommand = ($hardware eq "radinoCC1101" ? "avrdude -c avr109 -b [BAUDRATE] -P [PORT] -p atmega32u4 -vv -D -U flash:w:[HEXFILE] 2>[LOGFILE]" : "avrdude -c arduino -b [BAUDRATE] -P [PORT] -p atmega328p -vv -U flash:w:[HEXFILE] 2>[LOGFILE]"); + + # get User defined Flashcommand + my $flashCommand = AttrVal($name,"flashCommand",$defaultflashCommand); + + if ($defaultflashCommand eq $flashCommand) { + $hash->{logMethod}->($name, 5, "$name: PrepareFlash, standard flashCommand is used to flash."); + } else { + $hash->{logMethod}->($name, 3, "$name: PrepareFlash, custom flashCommand is manual defined! $flashCommand"); + } + + DevIo_CloseDev($hash); + if ($hardware eq "radinoCC1101" && $^O eq 'linux') { + $hash->{logMethod}->($name, 3, "$name: PrepareFlash, forcing special reset for $hardware on $port"); + # Mit dem Linux-Kommando 'stty' die Port-Einstellungen setzen + use IPC::Open3; + + my($chld_out, $chld_in, $chld_err); + use Symbol 'gensym'; + $chld_err = gensym; + my $pid; + eval { + $pid = open3($chld_in,$chld_out, $chld_err, "stty -F $port ospeed 1200 ispeed 1200"); + close($chld_in); # give end of file to kid, or feed him + }; + if ($@) { + $hash->{helper}{stty_output}=$@; + } else { + my @outlines = <$chld_out>; # read till EOF + my @errlines = <$chld_err>; # XXX: block potential if massive + $hash->{helper}{stty_pid}=$pid; + $hash->{helper}{stty_output} = join(" ",@outlines).join(" ",@errlines); + } + $port =~ s/usb-Unknown_radino/usb-In-Circuit_radino/g; + $hash->{logMethod}->($name ,3, "$name: PrepareFlash, changed usb port to \"$port\" for avrdude flashcommand compatible with radino"); + } + $hash->{helper}{avrdudecmd} = $flashCommand; + $hash->{helper}{avrdudecmd}=~ s/\Q[PORT]\E/$port/g; + $hash->{helper}{avrdudecmd} =~ s/\Q[HEXFILE]\E/$hexFile/g; + if ($hardware =~ "^nano" && $^O eq 'linux') { + $hash->{logMethod}->($name ,5, "$name: PrepareFlash, try additional flash with baudrate 115200 for optiboot"); + $hash->{helper}{avrdudecmd} = $hash->{helper}{avrdudecmd}." || ". $hash->{helper}{avrdudecmd}; + $hash->{helper}{avrdudecmd} =~ s/\Q[BAUDRATE]\E/$baudrate/; + $baudrate=115200; + } + $hash->{helper}{avrdudecmd} =~ s/\Q[BAUDRATE]\E/$baudrate/; + $log .= "command: $hash->{helper}{avrdudecmd}\n\n"; + InternalTimer(gettimeofday() + 1,"SIGNALduino_avrdude",$name); + $hash->{helper}{avrdudelogs} = $log; + return undef; +} #$hash,$name,"sendmsg","P17;R6#".substr($arg,2) ############################### sub SIGNALduino_Set($$@) { - my ($hash,$name, @a) = @_; - - return "\"set SIGNALduino\" needs at least one parameter" if(@a < 1); + my ($hash,$name, @a) = @_; - #SIGNALduino_Log3 $hash, 3, "$name: Set, called with params @a"; + return "\"set SIGNALduino\" needs at least one parameter" if(@a < 1); + + if (!InternalVal($name,"cc1101_available",0) && $a[0] =~ /^cc1101/) { + return "This command is only available with a cc1101 receiver"; + } + if (!exists($sets{$a[0]})) { + return "Unknown argument $a[0], choose one of supported commands"; + } + my $rcode=undef; + if ( ( (exists($hash->{DevState}) && $hash->{DevState} eq "initialized") || $a[0] eq "?" || $a[0] eq 'reset'|| $a[0] eq 'flash') && ref @{$sets{$a[0]}}[1] eq "CODE") { #Todo uninitalized value + $rcode= @{$sets{$a[0]}}[1]->($hash,@a); + } elsif ($hash->{DevState} ne "initialized") { + $rcode= "$name is not active, may firmware is not supported, please flash or reset"; + } + + return $rcode; # We will exit here, and give an output only, $rcode has some value +} - my $CC1101Frequency; - if (exists($hash->{hasCC1101}) && InternalVal($name,"hasCC1101",0)) { - if (!defined($hash->{cc1101_frequency})) { - $CC1101Frequency = "433"; - } else { - $CC1101Frequency = $hash->{cc1101_frequency}; - } - } - my %my_sets = %sets; - %my_sets = ( %my_sets, %{$hash->{additionalSets}} ) if ( defined($hash->{additionalSets}) ); - - if (!defined($my_sets{$a[0]})) { - my $arguments = ' '; - foreach my $arg (sort keys %my_sets) { - next if ($arg =~ m/cc1101/ && !InternalVal($name,"hasCC1101",0)); - if ($arg =~ m/patable/) { - next if (substr($arg, -3) ne $CC1101Frequency); - } - $arguments.= $arg . ($my_sets{$arg} ? (':' . $my_sets{$arg}) : '') . ' '; - } - #SIGNALduino_Log3 $hash, 3, "$name: Set, arg = $arguments"; - return "Unknown argument $a[0], choose one of " . $arguments; - } +############################### +sub SIGNALduino_Set_FhemWebList { + my ($hash, @a) = @_; + my @cList = sort map { "$_:@{$sets{$_}}[0]" } grep { + ($_ ne "?" && + ( + ( IsDummy($hash->{NAME}) && $_ =~ m/^(?:close|reset)/ ) || + ( InternalVal($hash->{NAME},"cc1101_available",0) || (!InternalVal($hash->{NAME},"cc1101_available",0) && $_ !~ /^cc/)) && + ( !IsDummy($hash->{NAME}) && (defined(DevIo_IsOpen($hash)) || $_ =~ m/^(?:flash|reset)/) ) + ) + ) + } keys %sets; + map { + my $set_key=$_; + my ($index) = grep { $cList[$_] =~ /^$set_key:/ } (0 .. $#cList-1); + $cList[$index] = "$set_key:".$hash->{additionalSets}{$set_key} if (defined($index)); + } keys %{$hash->{additionalSets}}; + return "Unknown argument $a[0], choose one of " . join(" ", @cList); +} - my $cmd = shift @a; - my $arg = join(" ", @a); - - if ($cmd =~ m/cc1101/ && !InternalVal($name,"hasCC1101",0)) { - return "This command is only available with a cc1101 receiver"; - } - - return "$name is not active, may firmware is not suppoted, please flash or reset" if ($cmd ne 'reset' && $cmd ne 'flash' && exists($hash->{DevState}) && $hash->{DevState} ne 'initialized'); +sub SIGNALduino_Set_raw { + my ($hash, @a) = @_; + $hash->{logMethod}->($hash->{NAME}, 4, "$hash->{NAME}: Set_raw, ".join(" ",@a)); + SIGNALduino_AddSendQueue($hash,$a[1]); + return undef; +} - if ($cmd =~ m/^cc1101_/) { - $cmd = substr($cmd,7); - } - - if($cmd eq "raw") { - $hash->{logMethod}->($name, 4, "$name: Set, $cmd $arg"); - #SIGNALduino_SimpleWrite($hash, $arg); - SIGNALduino_AddSendQueue($hash,$arg); - } elsif( $cmd eq "flash" ) { - my @args = split(' ', $arg); - my $log = ""; - my $hexFile = ""; - my ($port,undef) = split('@', $hash->{DeviceName}); - my $hardware=AttrVal($name,"hardware",""); - my $baudrate= 57600; - return "Please define your hardware! (attr $name hardware ) " if ($hardware eq ""); +############################### + sub SIGNALduino_Set_flash { + my ($hash, @a) = @_; + my $name = $hash->{NAME}; + return "Please define your hardware! (attr $name hardware ) " if (AttrVal($name,"hardware","") eq ""); + + my @args = @a[1..$#a]; return "ERROR: argument failed! flash [hexFile|url]" if (!$args[0]); - - if( grep $args[0] eq $_ , split(",",$my_sets{flash}) ) + + my %http_param = ( + timeout => 5, + hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat + method => "GET", # Lesen von Inhalten + header => "User-Agent: perl_fhem\r\nAccept: application/json", # Den Header gemaess abzufragender Daten aendern + ); + + my $hexFile = ""; + if( grep $args[0] eq $_ , split(",",$hash->{additionalSets}{flash}) ) { - $hash->{logMethod}->($hash, 3, "$name: Set, flash $args[0] try to fetch github assets for tag $args[0]"); - + $hash->{logMethod}->($hash, 3, "$name: Set_flash, $args[0] try to fetch github assets for tag $args[0]"); my $ghurl = "https://api.github.com/repos/RFD-FHEM/SIGNALDuino/releases/tags/$args[0]"; + $hash->{logMethod}->($hash, 3, "$name: Set_flash, $args[0] try to fetch release $ghurl"); - $hash->{logMethod}->($hash, 3, "$name: Set, flash $args[0] try to fetch release $ghurl"); - - my $http_param = { - url => $ghurl, - timeout => 5, - hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat - method => "GET", # Lesen von Inhalten - header => "User-Agent: perl_fhem\r\nAccept: application/json", # Den Header gemaess abzufragender Daten aendern - callback => \&SIGNALduino_githubParseHttpResponse, # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten - command => "getReleaseByTag" - - }; - HttpUtils_NonblockingGet($http_param); # Starten der HTTP Abfrage. Es gibt keinen Return-Code. + $http_param{url} = $ghurl; + $http_param{callback} = \&SIGNALduino_githubParseHttpResponse; # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten + $http_param{command} = "getReleaseByTag"; + HttpUtils_NonblockingGet(\%http_param); # Starten der HTTP Abfrage. Es gibt keinen Return-Code. return; - } + } elsif ($args[0] =~ m/^https?:\/\// ) { - my $http_param = { - url => $args[0], - timeout => 5, - hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat - method => "GET", # Lesen von Inhalten - callback => \&SIGNALduino_ParseHttpResponse, # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten - command => 'flash', - }; - - HttpUtils_NonblockingGet($http_param); - return; + $http_param{url} = $args[0]; + $http_param{callback} = \&SIGNALduino_ParseHttpResponse; # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten + $http_param{command} = "flash"; + HttpUtils_NonblockingGet(\%http_param); + return; } else { $hexFile = $args[0]; } - $hash->{logMethod}->($name, 3, "$name: Set, filename $hexFile provided, trying to flash"); - + $hash->{logMethod}->($name, 3, "$name: Set_flash, filename $hexFile provided, trying to flash"); # Only for Arduino , not for ESP - if ($hardware =~ m/(?:nano|mini|radino)/) + if (AttrVal($name,"hardware","") =~ m/(?:nano|mini|radino)/) { - - my $avrdudefound=0; - my $tool_name = "avrdude"; - my $path_separator = ':'; - if ($^O eq 'MSWin32') { - $tool_name .= ".exe"; - $path_separator = ';'; - } - for my $path ( split /$path_separator/, $ENV{PATH} ) { - if ( -f "$path/$tool_name" && -x _ ) { - $avrdudefound=1; - last; - } - } - $hash->{logMethod}->($name, 5, "$name: Set, avrdude found = $avrdudefound"); - return "avrdude is not installed. Please provide avrdude tool example: sudo apt-get install avrdude" if($avrdudefound == 0); - - $log .= "flashing Arduino $name\n"; - $log .= "hex file: $hexFile\n"; - $log .= "port: $port\n"; - - # prepare default Flashcommand - my $defaultflashCommand = ($hardware eq "radinoCC1101" ? "avrdude -c avr109 -b [BAUDRATE] -P [PORT] -p atmega32u4 -vv -D -U flash:w:[HEXFILE] 2>[LOGFILE]" : "avrdude -c arduino -b [BAUDRATE] -P [PORT] -p atmega328p -vv -U flash:w:[HEXFILE] 2>[LOGFILE]"); - - # get User defined Flashcommand - my $flashCommand = AttrVal($name,"flashCommand",$defaultflashCommand); - - if ($defaultflashCommand eq $flashCommand) { - $hash->{logMethod}->($name, 5, "$name: Set, standard flashCommand is used to flash."); - } else { - $hash->{logMethod}->($name, 3, "$name: Set, custom flashCommand is manual defined! $flashCommand"); - } - - DevIo_CloseDev($hash); - if ($hardware eq "radinoCC1101" && $^O eq 'linux') { - $hash->{logMethod}->($name, 3, "$name: Set, forcing special reset for $hardware on $port"); - # Mit dem Linux-Kommando 'stty' die Port-Einstellungen setzen - use IPC::Open3; - - my($chld_out, $chld_in, $chld_err); - use Symbol 'gensym'; - $chld_err = gensym; - my $pid; - eval { - $pid = open3($chld_in,$chld_out, $chld_err, "stty -F $port ospeed 1200 ispeed 1200"); - close($chld_in); # give end of file to kid, or feed him - }; - if ($@) { - $hash->{helper}{stty_output}=$@; - } else { - my @outlines = <$chld_out>; # read till EOF - my @errlines = <$chld_err>; # XXX: block potential if massive - $hash->{helper}{stty_pid}=$pid; - $hash->{helper}{stty_output} = join(" ",@outlines).join(" ",@errlines); - } - $port =~ s/usb-Unknown_radino/usb-In-Circuit_radino/g; - $hash->{logMethod}->($name ,3, "$name: Set, changed usb port to \"$port\" for avrdude flashcommand compatible with radino"); - } - $hash->{helper}{avrdudecmd} = $flashCommand; - $hash->{helper}{avrdudecmd}=~ s/\Q[PORT]\E/$port/g; - $hash->{helper}{avrdudecmd} =~ s/\Q[HEXFILE]\E/$hexFile/g; - if ($hardware =~ "^nano" && $^O eq 'linux') { - $hash->{logMethod}->($name ,5, "$name: Set, try additional flash with baudrate 115200 for optiboot"); - $hash->{helper}{avrdudecmd} = $hash->{helper}{avrdudecmd}." || ". $hash->{helper}{avrdudecmd}; - $hash->{helper}{avrdudecmd} =~ s/\Q[BAUDRATE]\E/$baudrate/; - $baudrate=115200; - } - $hash->{helper}{avrdudecmd} =~ s/\Q[BAUDRATE]\E/$baudrate/; - $log .= "command: $hash->{helper}{avrdudecmd}\n\n"; - InternalTimer(gettimeofday() + 1,"SIGNALduino_flash",$name); - $hash->{helper}{avrdudelogs} = $log; - return undef; + SIGNALduino_PrepareFlash($hash,$hexFile); } else { FW_directNotify("FILTER=$name", "#FHEMWEB:WEB", "FW_okDialog('ERROR:
Sorry, flashing your ESP is currently not supported.
The file is only downloaded in /opt/fhem/FHEM/firmware.')", ""); return "Sorry, Flashing your ESP via Module is currently not supported."; # processed in tests } - - } elsif ($cmd =~ m/reset/i) { +} + + +############################### +sub SIGNALduino_Set_reset +{ + my $hash = shift; delete($hash->{initResetFlag}) if defined($hash->{initResetFlag}); return SIGNALduino_ResetDevice($hash); - } elsif( $cmd eq "close" ) { - $hash->{DevState} = 'closed'; - return SIGNALduino_CloseDevice($hash); - } elsif( $cmd eq "disableMessagetype" ) { - my $argm = 'CD' . substr($arg,-1,1); - #SIGNALduino_SimpleWrite($hash, $argm); - SIGNALduino_AddSendQueue($hash,$argm); - $hash->{logMethod}->($name, 4, "$name: Set, $cmd $arg $argm"); - } elsif( $cmd eq "enableMessagetype" ) { - my $argm = 'CE' . substr($arg,-1,1); - #SIGNALduino_SimpleWrite($hash, $argm); - SIGNALduino_AddSendQueue($hash,$argm); - $hash->{logMethod}->($name, 4, "$name: Set, $cmd $arg $argm"); - } elsif( $cmd eq "freq" ) { - if ($arg eq "") { - $arg = AttrVal($name,"cc1101_frequency", 433.92); - } - my $f = $arg/26*65536; - my $f2 = sprintf("%02x", $f / 65536); - my $f1 = sprintf("%02x", int($f % 65536) / 256); - my $f0 = sprintf("%02x", $f % 256); - $arg = sprintf("%.3f", (hex($f2)*65536+hex($f1)*256+hex($f0))/65536*26); - $hash->{logMethod}->($name, 3, "$name: Set, Setting FREQ2..0 (0D,0E,0F) to $f2 $f1 $f0 = $arg MHz"); - SIGNALduino_AddSendQueue($hash,"W0F$f2"); - SIGNALduino_AddSendQueue($hash,"W10$f1"); - SIGNALduino_AddSendQueue($hash,"W11$f0"); - SIGNALduino_WriteInit($hash); - } elsif( $cmd eq "bWidth" ) { - SIGNALduino_AddSendQueue($hash,"C10"); - $hash->{getcmd}->{cmd} = "bWidth"; - $hash->{getcmd}->{arg} = $arg; - } elsif( $cmd eq "rAmpl" ) { - return "a numerical value between 24 and 42 is expected" if($arg !~ m/^\d+$/ || $arg < 24 || $arg > 42); - my ($v, $w); - for($v = 0; $v < @ampllist; $v++) { - last if($ampllist[$v] > $arg); - } - $v = sprintf("%02d", $v-1); - $w = $ampllist[$v]; - $hash->{logMethod}->($name, 3, "$name: Set, Setting AGCCTRL2 (1B) to $v / $w dB"); - SIGNALduino_AddSendQueue($hash,"W1D$v"); - SIGNALduino_WriteInit($hash); - } elsif( $cmd eq "sens" ) { - return "a numerical value between 4 and 16 is expected" if($arg !~ m/^\d+$/ || $arg < 4 || $arg > 16); - my $w = int($arg/4)*4; - my $v = sprintf("9%d",$arg/4-1); - $hash->{logMethod}->($name, 3, "$name: Set, Setting AGCCTRL0 (1D) to $v / $w dB"); - SIGNALduino_AddSendQueue($hash,"W1F$v"); - SIGNALduino_WriteInit($hash); - } elsif( substr($cmd,0,7) eq "patable" ) { - my $paFreq = substr($cmd,8); - my $pa = "x" . $patable{$paFreq}{$arg}; - $hash->{logMethod}->($name, 3, "$name: Set, Setting patable $paFreq $arg $pa"); - SIGNALduino_AddSendQueue($hash,$pa); - SIGNALduino_WriteInit($hash); - } elsif( $cmd eq "sendMsg" ) { - $hash->{logMethod}->($name, 5, "$name: Set, sendmsg msg=$arg"); - +} + +############################### +sub SIGNALduino_Set_sendMsg { + my ($hash, @a) = @_; + $hash->{logMethod}->($hash->{NAME}, 5, "$hash->{NAME}: Set_sendMsg, msg=$a[1]"); + # Split args in serval variables my ($protocol,$data,$repeats,$clock,$frequency,$datalength,$dataishex); my $n=0; - foreach my $s (split "#", $arg) { + foreach my $s (split "#", $a[1]) { my $c = substr($s,0,1); if ($n == 0 ) { # protocol $protocol = substr($s,1); @@ -756,7 +729,7 @@ sub SIGNALduino_Set($$@) { $data = $s; if ( substr($s,0,2) eq "0x" ) { $dataishex=1; $data=substr($data,2); } else { $dataishex=0; } - + } else { if ($c eq 'R') { $repeats = substr($s,1); } elsif ($c eq 'C') { $clock = substr($s,1); } @@ -765,42 +738,33 @@ sub SIGNALduino_Set($$@) { } $n++; } - return "$name: sendmsg, unknown protocol: $protocol" if (!exists($ProtocolListSIGNALduino{$protocol})); + return "$hash->{NAME}: sendmsg, unknown protocol: $protocol" if (!exists($ProtocolListSIGNALduino{$protocol})); $repeats=1 if (!defined($repeats)); - if (exists($ProtocolListSIGNALduino{$protocol}{frequency}) && InternalVal($name,"hasCC1101",0) && !defined($frequency)) { + if (exists($ProtocolListSIGNALduino{$protocol}{frequency}) && InternalVal($hash->{NAME},"cc1101_available",0) && !defined($frequency)) { $frequency = $ProtocolListSIGNALduino{$protocol}{frequency}; } - if (defined($frequency) && InternalVal($name,"hasCC1101",0)) { + if (defined($frequency) && InternalVal($hash->{NAME},"cc1101_available",0)) { $frequency="F=$frequency;"; } else { $frequency=""; } - - #print ("data = $data \n"); - #print ("protocol = $protocol \n"); - #print ("repeats = $repeats \n"); - + my %signalHash; my %patternHash; my $pattern=""; my $cnt=0; - + my $sendData; if (exists($ProtocolListSIGNALduino{$protocol}{format}) && $ProtocolListSIGNALduino{$protocol}{format} eq 'manchester') { - #$clock = (map { $clock += $_ } @{$ProtocolListSIGNALduino{$protocol}{clockrange}}) / 2 if (!defined($clock)); - $clock += $_ for(@{$ProtocolListSIGNALduino{$protocol}{clockrange}}); $clock = round($clock/2,0); - if ($protocol == 43) { - #$data =~ tr/0123456789ABCDEF/FEDCBA9876543210/; - } - + my $intro = ""; my $outro = ""; - + $intro = $ProtocolListSIGNALduino{$protocol}{msgIntro} if ($ProtocolListSIGNALduino{$protocol}{msgIntro}); $outro = $ProtocolListSIGNALduino{$protocol}{msgOutro}.";" if ($ProtocolListSIGNALduino{$protocol}{msgOutro}); @@ -811,7 +775,7 @@ sub SIGNALduino_Set($$@) { } $sendData = $intro . "SM;" . ($repeats > 0 ? "R=$repeats;" : "") . "C=$clock;D=$data;" . $outro . $frequency; # SM;R=2;C=400;D=AFAFAF; - $hash->{logMethod}->($name, 5, "$name: Set, sendmsg Preparing manchester protocol=$protocol, repeats=$repeats, clock=$clock data=$data"); + $hash->{logMethod}->($hash->{NAME}, 5, "$hash->{NAME}: Set_sendMsg, Preparing manchester protocol=$protocol, repeats=$repeats, clock=$clock data=$data"); } else { if ($protocol == 3 || substr($data,0,2) eq "is") { @@ -819,234 +783,445 @@ sub SIGNALduino_Set($$@) { $data = substr($data,2); # is am Anfang entfernen } $data = SIGNALduino_ITV1_tristateToBit($data); - $hash->{logMethod}->($name, 5, "$name: Set, sendmsg IT V1 convertet tristate to bits=$data"); + $hash->{logMethod}->($hash->{NAME}, 5, "$hash->{NAME}: Set_sendMsg, IT V1 convertet tristate to bits=$data"); } if (!defined($clock)) { $hash->{ITClock} = 250 if (!defined($hash->{ITClock})); # Todo: Klaeren wo ITClock verwendet wird und ob wir diesen Teil nicht auf Protokoll 3,4 und 17 minimieren $clock=$ProtocolListSIGNALduino{$protocol}{clockabs} > 1 ?$ProtocolListSIGNALduino{$protocol}{clockabs}:$hash->{ITClock}; } - - if ($dataishex == 1) + + if ($dataishex == 1) { # convert hex to bits my $hlen = length($data); my $blen = $hlen * 4; $data = unpack("B$blen", pack("H$hlen", $data)); } + $hash->{logMethod}->($hash->{NAME}, 5, "$hash->{NAME}: Set_sendMsg, Preparing rawsend command for protocol=$protocol, repeats=$repeats, clock=$clock bits=$data"); - $hash->{logMethod}->($name, 5, "$name: Set, sendmsg Preparing rawsend command for protocol=$protocol, repeats=$repeats, clock=$clock bits=$data"); - foreach my $item (qw(preSync sync start one zero float pause end universal)) { - #print ("item= $item \n"); next if (!exists($ProtocolListSIGNALduino{$protocol}{$item})); - + foreach my $p (@{$ProtocolListSIGNALduino{$protocol}{$item}}) { - #print (" p = $p \n"); - if (!exists($patternHash{$p})) { $patternHash{$p}=$cnt; - $pattern.="P".$patternHash{$p}."=".$p*$clock.";"; + $pattern.="P".$patternHash{$p}."=". int($p*$clock) .";"; $cnt++; } $signalHash{$item}.=$patternHash{$p}; - #print (" signalHash{$item} = $signalHash{$item} \n"); } } my @bits = split("", $data); - + my %bitconv = (1=>"one", 0=>"zero", 'D'=> "float", 'F'=> "float", 'P'=> "pause", 'U'=> "universal"); my $SignalData="D="; - + $SignalData.=$signalHash{preSync} if (exists($signalHash{preSync})); $SignalData.=$signalHash{sync} if (exists($signalHash{sync})); $SignalData.=$signalHash{start} if (exists($signalHash{start})); foreach my $bit (@bits) { next if (!exists($bitconv{$bit})); - #SIGNALduino_Log3 $name, 5, "$name: Set, encoding $bit"; $SignalData.=$signalHash{$bitconv{$bit}}; ## Add the signal to our data string } $SignalData.=$signalHash{end} if (exists($signalHash{end})); $sendData = "SR;R=$repeats;$pattern$SignalData;$frequency"; } - - - #SIGNALduino_SimpleWrite($hash, $sendData); SIGNALduino_AddSendQueue($hash,$sendData); - $hash->{logMethod}->($name, 4, "$name: Set, sending via SendMsg: $sendData"); - } else { - $hash->{logMethod}->($name, 5, "$name: Set, $cmd $arg"); - #SIGNALduino_SimpleWrite($hash, $arg); - return "Unknown argument $cmd, choose one of ". ReadingsVal($name,'cmd',' help me'); - } - - return undef; + $hash->{logMethod}->($hash->{NAME}, 4, "$hash->{NAME}: Set_sendMsg, sending : $sendData"); } +############################### +sub SIGNALduino_Set_close { + my $hash = shift; + $hash->{DevState} = 'closed'; + return SIGNALduino_CloseDevice($hash); +} + +############################### +sub SIGNALduino_Set_MessageType +{ + my ($hash, @a) = @_; + my $argm; + if ($a[0] =~ /^enable/) { + $argm = 'CE' . substr($a[1],-1,1); + } else { + $argm = 'CD' . substr($a[1],-1,1); + } + SIGNALduino_AddSendQueue($hash,$argm); + $hash->{logMethod}->($hash->{NAME}, 4, "$hash->{NAME}: Set_MessageType, $a[0] $a[1] $argm"); +} + +############################### +sub SIGNALduino_Set_bWidth +{ + my ($hash, @a) = @_; + + if (exists($hash->{ucCmd}->{cmd}) && $hash->{ucCmd}->{cmd} eq "set_bWidth" && $a[0] =~ /^C10\s=\s([A-Fa-f0-9]{2})$/ ) + { + my ($ob,$bw) = cc1101::CalcbWidthReg($hash,$1,$hash->{ucCmd}->{arg}); + $hash->{logMethod}->($hash->{NAME}, 3, "$hash->{NAME}: Set_bWidth, bWidth: Setting MDMCFG4 (10) to $ob = $bw KHz"); + # Toddo setRegisters verwenden + main::SIGNALduino_AddSendQueue($hash,"W12$ob"); + main::SIGNALduino_WriteInit($hash); + return ("Setting MDMCFG4 (10) to $ob = $bw KHz" ,undef); + } else { + $hash->{logMethod}->($hash->{NAME}, 3, "$hash->{NAME}: Set_bWidth, Request register 10"); + # Get Register 10 + cc1101::GetRegister($hash,10); + + $hash->{ucCmd}->{cmd} = "set_bWidth"; + $hash->{ucCmd}->{arg} = $a[1]; # Zielbandbreite + $hash->{ucCmd}->{responseSub} = \&SIGNALduino_Set_bWidth; # Callback auf sich selbst setzen + $hash->{ucCmd}->{asyncOut} = $hash->{CL} if (defined($hash->{CL})); + $hash->{ucCmd}->{timenow}=time(); + #return "Register 10 requested"; + return undef; + } +} + + ############################### sub SIGNALduino_Get($@) { - my ($hash, @a) = @_; - my $type = $hash->{TYPE}; - my $name = $hash->{NAME}; - return "$name is not active, may firmware is not suppoted, please flash or reset" if (exists($hash->{DevState}) && $hash->{DevState} ne 'initialized'); - - $hash->{logMethod}->($name, 5, "$name: Get, $type\" needs at least one parameter") if(@a < 2); - return "\"get $type\" needs at least one parameter" if(@a < 2); - if(!defined($gets{$a[1]})) { - Log3 ($name, 5, "Unknown argument $a[1] for $a[0]") if ($a[1] ne "?"); - my @cList = sort map { $_ =~ m/^(raw|ccreg)$/ ? $_ : "$_:noArg" } grep { (( InternalVal($a[0],"hasCC1101",0) || (!InternalVal($a[0],"hasCC1101",0) && $_ !~ /^cc/)) && (!IsDummy($a[0]) || IsDummy($a[0]) && $_ =~ m/^(availableFirmware|raw)/)) } keys %gets; - return "Unknown argument $a[1], choose one of " . join(" ", @cList); - } - return "no command to send, get aborted." if (ref $gets{$a[1]} eq 'ARRAY' && length($gets{$a[1]}[0]) == 0 && length($a[2]) == 0); - - if (($a[1] eq "ccconf" || $a[1] eq "ccreg" || $a[1] eq "ccpatable") && !InternalVal($name,"hasCC1101",0)) { + my ($hash,$name, @a) = @_; + #my $type = $hash->{TYPE}; + + return "\"get SIGNALduino\" needs at least one parameter" if(@a < 1); + + if (!InternalVal($name,"cc1101_available",0) && $a[0] =~ /^cc/) { return "This command is only available with a cc1101 receiver"; } - - if (ref $gets{$a[1]} eq 'ARRAY') { # Option 1 - $hash->{logMethod}->($name, 5, "$name: Get, command for gets: " . $gets{$a[1]}[0] . " " . $a[2]); - SIGNALduino_AddSendQueue($hash, $gets{$a[1]}[0] . $a[2]); - $hash->{getcmd}->{cmd}=$a[1]; - $hash->{getcmd}->{asyncOut}=$hash->{CL}; - $hash->{getcmd}->{timenow}=time(); - } elsif ( ref $gets{$a[1]} eq 'CODE') { # Option 2 - return $gets{$a[1]}->($hash,@a); + if (!exists($gets{$a[0]})) { + return "Unknown argument $a[0], choose one of supported commands"; } - return undef; # We will exit here, and give an output only, if any output is supported. If this is not supported, only the readings are updated + my $rcode=undef; + if (exists($hash->{ucCmd}) && $a[0] ne "?" ) { + SIGNALduino_Get_delayed("SIGNALduino_Get_delayed:$name:".join(":",@a)); + } + elsif ( ($hash->{DevState} eq "initialized" || $a[0] eq "?" || $a[0] eq 'availableFirmware') && ref @{$gets{$a[0]}}[1] eq "CODE") { # + $rcode= @{$gets{$a[0]}}[1]->($hash,@a); + } elsif ($hash->{DevState} ne "initialized") { + $rcode= "$name is not active, may firmware is not supported, please flash or reset"; + } + + return $rcode; # We will exit here, and give an output only, $rcode has some value +} + + + +############################### +#SIGNALduino_Get_Callback($name, $callbackFn, @args); +sub SIGNALduino_Get_Callback($$$) { + my ($name, $callbackFn, $arg) = @_; + + my @a = split (" ",$arg); + return "\"get _Get_Callback\" needs at least two parameters" if(@a < 2); + return "\"$name\" is not a definition of type SIGNALduino" if (!IsDevice($name, "SIGNALduino")); + + my $hash = $defs{$name}; + my $rcode = SIGNALduino_Get($hash,$name,@a); + + if (!defined($rcode)) + { + $hash->{ucCmd}->{responseSub}=$callbackFn; + delete($hash->{ucCmd}->{asyncOut}); + } + + return $rcode; # We will exit here, and give an output only, $rcode has some value +} + + +############################### +sub SIGNALduino_Get_FhemWebList { + my ($hash, @a) = @_; + my @cList = sort map { "$_:@{$gets{$_}}[0]" } grep { + ($_ ne "?" && + ( + (IsDummy($hash->{NAME}) && $_ =~ m/^(?:availableFirmware|raw)/) || + ( InternalVal($hash->{NAME},"cc1101_available",0) || (!InternalVal($hash->{NAME},"cc1101_available",0) && $_ !~ /^cc/)) && + ( !IsDummy($hash->{NAME}) && (defined(DevIo_IsOpen($hash)) || $_ =~ m/^(?:availableFirmware|raw)/ )) ) + ) + } keys %gets; + return "Unknown argument $a[0], choose one of " . join(" ", @cList); +} + + +############################### +sub SIGNALduino_Get_availableFirmware { + my ($hash, @a) = @_; + + if ($missingModulSIGNALduino =~ m/JSON/ ) + { + $hash->{logMethod}->($hash->{NAME}, 1, "$hash->{NAME}: get $a[0] failed. Pleas install Perl module JSON. Example: sudo apt-get install libjson-perl"); + return "$a[0]: \n\nFetching from github is not possible. Please install JSON. Example:
sudo apt-get install libjson-perl"; + } + + my $channel=AttrVal($hash->{NAME},"updateChannelFW","stable"); + my $hardware=AttrVal($hash->{NAME},"hardware",undef); + + my ($validHw) = $modules{$hash->{TYPE}}{AttrList} =~ /.*hardware:(.*?)\s/; + $hash->{logMethod}->($hash->{NAME}, 1, "$hash->{NAME}: found availableFirmware for $validHw"); + + if (!defined($hardware) || $validHw !~ /$hardware(?:,|$)/ ) + { + $hash->{logMethod}->($hash->{NAME}, 1, "$hash->{NAME}: get $a[0] failed. Please set attribute hardware first"); + return "$a[0]: \n\n$hash->{NAME}: get $a[0] failed. Please choose one of $validHw attribute hardware"; + } + SIGNALduino_querygithubreleases($hash); + return "$a[0]: \n\nFetching $channel firmware versions for $hardware from github\n"; } ############################### -sub SIGNALduino_parseResponse($$$) { - my $hash = shift; - my $cmd = shift; - my $msg = shift; - +sub SIGNALduino_Get_Command +{ + my ($hash, @a) = @_; my $name=$hash->{NAME}; - - $msg =~ s/[\r\n]//g; - - if($cmd eq "cmds") - { # nice it up - $msg =~ s/$name cmds =>//g; - $msg =~ s/.*Use one of//g; - } - elsif($cmd eq "uptime") - { # decode it - #$msg = hex($msg); # /125; only for col or coc - $msg = sprintf("%d %02d:%02d:%02d", $msg/86400, ($msg%86400)/3600, ($msg%3600)/60, $msg%60); - } - elsif($cmd eq "ccregAll") - { - $msg =~ s/ /\n/g; - $msg = "\n\n" . $msg - } - elsif($cmd eq "ccconf") - { - my (undef,$str) = split('=', $msg); - my $var; - my %r = ( "0D"=>1,"0E"=>1,"0F"=>1,"10"=>1,"11"=>1,"1B"=>1,"1D"=>1 ); - $msg = ""; - foreach my $a (sort keys %r) { - $var = substr($str,(hex($a)-13)*2, 2); - $r{$a} = hex($var); - } - $msg = sprintf("freq:%.3fMHz bWidth:%dKHz rAmpl:%ddB sens:%ddB (DataRate:%.2fBaud)", - 26*(($r{"0D"}*256+$r{"0E"})*256+$r{"0F"})/65536, #Freq - 26000/(8 * (4+(($r{"10"}>>4)&3)) * (1 << (($r{"10"}>>6)&3))), #Bw - $ampllist[$r{"1B"}&7], #rAmpl - 4+4*($r{"1D"}&3), #Sens - ((256+$r{"11"})*(2**($r{"10"} & 15 )))*26000000/(2**28) #DataRate - ); - } - elsif($cmd eq "bWidth") { - my $val = hex(substr($msg,6)); - my $arg = $hash->{getcmd}->{arg}; - my $ob = $val & 0x0f; - - my ($bits, $bw) = (0,0); - OUTERLOOP: - for (my $e = 0; $e < 4; $e++) { - for (my $m = 0; $m < 4; $m++) { - $bits = ($e<<6)+($m<<4); - $bw = int(26000/(8 * (4+$m) * (1 << $e))); # KHz - last OUTERLOOP if($arg >= $bw); - } - } - - $ob = sprintf("%02x", $ob+$bits); - $msg = "Setting MDMCFG4 (10) to $ob = $bw KHz"; - $hash->{logMethod}->($name, 3, "$name: parseResponse, bWidth: Setting MDMCFG4 (10) to $ob = $bw KHz"); - delete($hash->{getcmd}); - SIGNALduino_AddSendQueue($hash,"W12$ob"); - SIGNALduino_WriteInit($hash); - } - elsif($cmd eq "ccpatable") { - my $CC1101Frequency = "433"; - if (defined($hash->{cc1101_frequency})) { - $CC1101Frequency = $hash->{cc1101_frequency}; - } - my $dBn = substr($msg,9,2); - $hash->{logMethod}->($name, 3, "$name: parseResponse, patable: $dBn"); - foreach my $dB (keys %{ $patable{$CC1101Frequency} }) { - if ($dBn eq $patable{$CC1101Frequency}{$dB}) { - $hash->{logMethod}->($name, 5, "$name: parseResponse, patable: $dB"); - $msg .= " => $dB"; - last; - } - } - # $msg .= "\n\n$CC1101Frequency MHz\n\n"; - # foreach my $dB (keys $patable{$CC1101Frequency}) - # { - # $msg .= "$patable{$CC1101Frequency}{$dB} $dB\n"; - # } - } - - return $msg; + return "Unsupported command for the microcontroller" if (!exists(${$gets{$a[0]}}[2])); + $hash->{logMethod}->($name, 5, "$name: Get $a[0] executed"); + SIGNALduino_AddSendQueue($hash, @{$gets{$a[0]}}[2] . (exists($a[1]) ? "$a[1]" : "")); + $hash->{ucCmd}->{cmd}=$a[0]; + $hash->{ucCmd}->{responseSub}=$gets{$a[0]}[3]; + $hash->{ucCmd}->{asyncOut}=$hash->{CL} if (defined($hash->{CL})); + $hash->{ucCmd}->{timenow}=time(); + return undef; } +############################### +sub SIGNALduino_Get_Command_CCReg +{ + my ($hash, @a) = @_; + my $name=$hash->{NAME}; + if (exists($cc1101_register{uc($_[2])}) || $_[2] =~ /^99$/ ) { + return SIGNALduino_Get_Command(@_); + } else { + return "unknown Register $_[2], please choose a valid cc1101 register"; + } +} + + +############################### +sub SIGNALduino_Get_Raw { + my ($hash, @a) = @_; + return "\"get raw\" needs at least a parameter" if (@a < 2); + if ($a[1] =~ /^M[CcSU];.*/) + { + $a[1]="\002$a[1]\003"; ## Add start end end marker if not already there + $hash->{logMethod}->($hash->{NAME}, 5, "$hash->{NAME}: msg adding start and endmarker to message"); + } + + if ($a[1] =~ /\002M.;.*;\003$/) + { + $hash->{logMethod}->( $hash->{NAME}, 4, "$hash->{NAME}: msg get raw: $a[1]"); + return SIGNALduino_Parse($hash, $hash, $hash->{NAME}, $a[1]); + } +} + + +############################### +sub SIGNALduino_GetResponseUpdateReading +{ + return ($_[1],1); +} + +############################### +sub SIGNALduino_Get_delayed($) { + my(undef,$name,@cmds) = split(':', shift); + my $hash = $defs{$name}; + + if ( exists($hash->{ucCmd}) && !exists($hash->{ucCmd}->{timenow}) ) { + $hash->{ucCmd}->{timenow}=time(); + Log3 ($hash->{NAME}, 5, "$name: Get_delayed, timenow was missing, set ".$hash->{ucCmd}->{timenow}); + } + + if (exists($hash->{ucCmd}) && $hash->{ucCmd}->{timenow}+10 > time() ) { + $hash->{logMethod}->($hash->{NAME}, 5, "$name: Get_delayed, ".join(" ",@cmds)." delayed"); + main::InternalTimer(main::gettimeofday() + main::SDUINO_GET_CONFIGQUERY_DELAY, "SIGNALduino_Get_delayed", "SIGNALduino_Get_delayed:$name:".join(" ",@cmds), 0); + } else { + delete($hash->{ucCmd}); + $hash->{logMethod}->($hash->{NAME}, 5, "$name: Get_delayed, ".join(" ",@cmds)." executed"); + RemoveInternalTimer("SIGNALduino_Get_delayed:$name:".join(" ",@cmds)); + SIGNALduino_Get($hash,$name,$cmds[0]); + } +} + +############################### +sub SIGNALduino_CheckUptimeResponse +{ + my $msg = sprintf("%d %02d:%02d:%02d", $_[1]/86400, ($_[1]%86400)/3600, ($_[1]%3600)/60, $_[1]%60); + #readingsSingleUpdate($_[0], $_[0]->{ucCmd}->{cmd}, $msg, 0); + return ($msg,0); +} + +############################### +sub SIGNALduino_CheckCmdsResponse +{ + my $hash = shift; + my $msg = shift; + my $name=$hash->{NAME}; + + $msg =~ s/$name cmds =>//g; + $msg =~ s/.*Use one of//g; + + return ($msg,0); +} + +############################### +sub SIGNALduino_CheckccConfResponse { + my (undef,$str) = split('=', $_[1]); + my $var; + my %r = ( "0D"=>1,"0E"=>1,"0F"=>1,"10"=>1,"11"=>1,"12"=>1,"1B"=>1,"1D"=>1, "15"=>1); + foreach my $a (sort keys %r) { + $var = substr($str,(hex($a)-13)*2, 2); + $r{$a} = hex($var); + } + my $msg = sprintf("Freq: %.3f MHz, Bandwidth: %d KHz, rAmpl: %d dB, sens: %d dB, DataRate: %.2f Baud", + 26*(($r{"0D"}*256+$r{"0E"})*256+$r{"0F"})/65536, #Freq | Register 0x0D,0x0E,0x0F + 26000/(8 * (4+(($r{"10"}>>4)&3)) * (1 << (($r{"10"}>>6)&3))), #Bw | Register 0x10 + $ampllist[$r{"1B"}&7], #rAmpl | Register 0x1B + 4+4*($r{"1D"}&3), #Sens | Register 0x1D + ((256+$r{"11"})*(2**($r{"10"} & 15 )))*26000000/(2**28) #DataRate | Register 0x10,0x11 + ); + + my $msg2 = sprintf("Modulation: %s, Syncmod: %s", + $modformat[$r{"12"}>>4], #Modulation | Register 0x12 + $syncmod[($r{"12"})&7], #Syncmod | Register 0x12 + ); + + readingsBeginUpdate($_[0]); + readingsBulkUpdate($_[0], "cc1101_config", $msg); + readingsBulkUpdate($_[0], "cc1101_config_ext", $msg2); + readingsEndUpdate($_[0], 1); + + return ($msg.", ".$msg2,undef); +} + +############################### +sub SIGNALduino_CheckccPatableResponse { + my $hash = shift; + my $msg = shift; + my $name=$hash->{NAME}; + + my $CC1101Frequency=AttrVal($name,"cc1101_frequency",433); + $CC1101Frequency = 433 if ($CC1101Frequency >= 433 && $CC1101Frequency <= 435); + $CC1101Frequency = 868 if ($CC1101Frequency >= 863 && $CC1101Frequency <= 870); + my $dBn = substr($msg,9,2); + $hash->{logMethod}->($name, 3, "$name: CheckCcpatableResponse, patable: $dBn"); + foreach my $dB (keys %{ $patable{$CC1101Frequency} }) { + if ($dBn eq $patable{$CC1101Frequency}{$dB}) { + $hash->{logMethod}->($name, 5, "$name: CheckCcpatableResponse, patable: $dB"); + $msg .= " => $dB"; + last; + } + } + readingsSingleUpdate($hash, "cc1101_patable", $msg,1); + return ($msg,undef); +} + +############################### +sub SIGNALduino_CheckCcregResponse +{ + my $hash = shift; + my $msg = shift; + my $name=$hash->{NAME}; + + if ($msg =~ /^ccreg/) { + + $msg =~ s/\s\sccreg/\nccreg/g; + $msg =~ s/ccreg\s\d0:\s//g; + + my @ccreg = split(/\s/,$msg); + + $msg.= "\n\n"; + $msg.= "Configuration Register Detail (address, name, value):\n"; + + my $reg_idx = 0; + foreach my $key (sort keys %cc1101_register) { + $msg.= "0x".$key." ".$cc1101_register{$key}. " - 0x".$ccreg[$reg_idx]."\n"; + $reg_idx++; + } + } else { + $msg =~ /^C([A-Fa-f0-9]{2}) = ([A-Fa-f0-9]{2})$/; + my $reg = $1; + my $val = $2; + $msg = "Configuration Register Detail address (name) = value:\n"; + $msg .= "0x$reg ( $cc1101_register{$reg}) = 0x$val\n"; + } + return ("\n".$msg,undef); +} + + + +############################### +### Unused ### +sub SIGNALduino_CheckSendRawResponse +{ + my $hash = shift; + my $msg = shift; + + if ($msg =~ /^S[RCM];/ ) + { + my $name=$hash->{NAME}; + + # zu testen der sendeQueue, kann wenn es funktioniert auf verbose 5 + $hash->{logMethod}->($name, 4, "$name: CheckSendrawResponse, sendraw answer: $msg"); + #RemoveInternalTimer("HandleWriteQueue:$name"); + delete($hash->{ucCmd}); + SIGNALduino_HandleWriteQueue("x:$name"); + } + return (undef); +} + ############################### sub SIGNALduino_ResetDevice($) { my $hash = shift; my $name = $hash->{NAME}; - if (!defined($hash->{helper}{resetInProgress})) - { + + if (!defined($hash->{helper}{resetInProgress})) { my $hardware = AttrVal($name,"hardware",""); - $hash->{logMethod}->($name, 3, "$name: ResetDevice, $hardware"); + $hash->{logMethod}->($name, 3, "$name: ResetDevice, $hardware"); + + if (IsDummy($name)) { # for dummy device + $hash->{DevState} = "initialized"; + readingsSingleUpdate($hash, "state", "opened", 1); + return undef; + } + DevIo_CloseDev($hash); if ($hardware eq "radinoCC1101" && $^O eq 'linux') { # The reset is triggered when the Micro's virtual (CDC) serial / COM port is opened at 1200 baud and then closed. # When this happens, the processor will reset, breaking the USB connection to the computer (meaning that the virtual serial / COM port will disappear). # After the processor resets, the bootloader starts, remaining active for about 8 seconds. # The bootloader can also be initiated by pressing the reset button on the Micro. - # Note that when the board first powers up, it will jump straight to the user sketch, if present, rather than initiating the bootloader. + # Note that when the board first powers up, it will jump straight to the user sketch, if present, rather than initiating the bootloader. my ($dev, $baudrate) = split("@", $hash->{DeviceName}); $hash->{logMethod}->($name, 3, "$name: ResetDevice, forcing special reset for $hardware on $dev"); # Mit dem Linux-Kommando 'stty' die Port-Einstellungen setzen system("stty -F $dev ospeed 1200 ispeed 1200"); $hash->{helper}{resetInProgress}=1; InternalTimer(gettimeofday()+10,"SIGNALduino_ResetDevice",$hash); - $hash->{logMethod}->($name, 3, "$name: ResetDevice, reopen delayed for 10 second"); - return; + $hash->{logMethod}->($name, 3, "$name: ResetDevice, reopen delayed for 10 second"); + return undef; } } else { delete($hash->{helper}{resetInProgress}); } DevIo_OpenDev($hash, 0, "SIGNALduino_DoInit", 'SIGNALduino_Connect'); + return undef; } ############################### sub SIGNALduino_CloseDevice($) { my ($hash) = @_; - $hash->{logMethod}->($hash->{NAME}, 2, "$hash->{NAME}: CloseDevice, closed"); + $hash->{logMethod}->($hash->{NAME}, 2, "$hash->{NAME}: CloseDevice, closed"); RemoveInternalTimer($hash); DevIo_CloseDev($hash); readingsSingleUpdate($hash, "state", "closed", 1); - + return undef; } @@ -1059,29 +1234,27 @@ sub SIGNALduino_DoInit($) { my ($ver, $try) = ("", 0); #Dirty hack to allow initialisation of DirectIO Device for some debugging and tesing - $hash->{logMethod}->($hash, 1, "$name: DoInit, ".$hash->{DEF}); - + delete($hash->{disConnFlag}) if defined($hash->{disConnFlag}); - + RemoveInternalTimer("HandleWriteQueue:$name"); @{$hash->{QUEUE}} = (); $hash->{sendworking} = 0; - + if (($hash->{DEF} !~ m/\@directio/) and ($hash->{DEF} !~ m/none/) ) { $hash->{logMethod}->($hash, 1, "$name: DoInit, ".$hash->{DEF}); $hash->{initretry} = 0; RemoveInternalTimer($hash); - + #SIGNALduino_SimpleWrite($hash, "XQ"); # Disable receiver InternalTimer(gettimeofday() + SDUINO_INIT_WAIT_XQ, "SIGNALduino_SimpleWrite_XQ", $hash, 0); - InternalTimer(gettimeofday() + SDUINO_INIT_WAIT, "SIGNALduino_StartInit", $hash, 0); } # Reset the counter delete($hash->{XMIT_TIME}); delete($hash->{NR_CMD_LAST_H}); - + return; return undef; } @@ -1092,7 +1265,7 @@ sub SIGNALduino_DoInit($) { sub SIGNALduino_SimpleWrite_XQ($) { my ($hash) = @_; my $name = $hash->{NAME}; - + $hash->{logMethod}->($hash, 3, "$name: SimpleWrite_XQ, disable receiver (XQ)"); SIGNALduino_SimpleWrite($hash, "XQ"); #DevIo_SimpleWrite($hash, "XQ\n",2); @@ -1103,7 +1276,7 @@ sub SIGNALduino_StartInit($) { my ($hash) = @_; my $name = $hash->{NAME}; $hash->{version} = undef; - + $hash->{logMethod}->($name,3 , "$name: StartInit, get version, retry = " . $hash->{initretry}); if ($hash->{initretry} >= SDUINO_INIT_MAXRETRY) { $hash->{DevState} = 'INACTIVE'; @@ -1119,22 +1292,84 @@ sub SIGNALduino_StartInit($) { return; } else { - $hash->{getcmd}->{cmd} = "version"; + $hash->{ucCmd}->{cmd} = "version"; + $hash->{ucCmd}->{responseSub} = \&SIGNALduino_CheckVersionResp; + $hash->{ucCmd}->{timenow} = time(); SIGNALduino_SimpleWrite($hash, "V"); #DevIo_SimpleWrite($hash, "V\n",2); $hash->{DevState} = 'waitInit'; RemoveInternalTimer($hash); - InternalTimer(gettimeofday() + SDUINO_CMD_TIMEOUT, "SIGNALduino_CheckCmdResp", $hash, 0); + InternalTimer(gettimeofday() + SDUINO_CMD_TIMEOUT, "SIGNALduino_CheckVersionResp", $hash, 0); } } ############################### +sub SIGNALduino_CheckVersionResp +{ + my ($hash,$msg) = @_; + my $name = $hash->{NAME}; + + + ### ToDo, manchmal kommen Mu Nachrichten in $msg und somit ist keine Version feststellbar !!! + if (defined($msg)) { + $hash->{logMethod}->($hash, 5, "$name: CheckVersionResp, called with $msg"); + $msg =~ m/($gets{$hash->{ucCmd}->{cmd}}[4])/; + $hash->{version} = $1; + } else { + $hash->{logMethod}->($hash, 5, "$name: CheckVersionResp, called without msg"); + # Aufruf durch Timeout! + $msg="undef"; + delete($hash->{ucCmd}); + } + + if (!defined($hash->{version}) ) { + $msg = "$name: CheckVersionResp, Not an SIGNALduino device, got for V: $msg"; + $hash->{logMethod}->($hash, 1, $msg); + readingsSingleUpdate($hash, "state", "no SIGNALduino found", 1); #uncoverable statement because state is overwritten by SIGNALduino_CloseDevice + $hash->{initretry} ++; + SIGNALduino_StartInit($hash); + } elsif($hash->{version} =~ m/^V 3\.1\./) { + $msg = "$name: CheckVersionResp, Version of your arduino is not compatible, please flash new firmware. (device closed) Got for V: $msg"; + readingsSingleUpdate($hash, "state", "unsupported firmware found", 1); #uncoverable statement because state is overwritten by SIGNALduino_CloseDevice + $hash->{logMethod}->($hash, 1, $msg); + $hash->{DevState} = 'INACTIVE'; + SIGNALduino_CloseDevice($hash); + } else { + if (exists($hash->{DevState}) && $hash->{DevState} eq 'waitInit') { + RemoveInternalTimer($hash); + } + + readingsSingleUpdate($hash, "state", "opened", 1); + $hash->{logMethod}->($name, 2, "$name: CheckVersionResp, initialized " . SDUINO_VERSION); + delete($hash->{initResetFlag}) if defined($hash->{initResetFlag}); + SIGNALduino_SimpleWrite($hash, "XE"); # Enable receiver + $hash->{logMethod}->($hash, 3, "$name: CheckVersionResp, enable receiver (XE) "); + delete($hash->{initretry}); + # initialize keepalive + $hash->{keepalive}{ok} = 0; + $hash->{keepalive}{retry} = 0; + InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash, 0); + if ($hash->{version} =~ m/cc1101/) { + $hash->{cc1101_available} = 1; + $hash->{logMethod}->($name, 5, "$name: CheckVersionResp, cc1101 available"); + SIGNALduino_Get($hash, $name,"ccconf"); + SIGNALduino_Get($hash, $name,"ccpatable"); + } + $hash->{DevState} = 'initialized'; + $msg = $hash->{version}; + } + return ($msg,undef); +} + + +############################### +# Todo: SUB kann entfernt werden sub SIGNALduino_CheckCmdResp($) { my ($hash) = @_; my $name = $hash->{NAME}; my $msg = undef; my $ver; - + if ($hash->{version}) { $ver = $hash->{version}; if ($ver !~ m/SIGNAL(duino|ESP)/) { @@ -1163,11 +1398,11 @@ sub SIGNALduino_CheckCmdResp($) { $hash->{keepalive}{ok} = 0; $hash->{keepalive}{retry} = 0; InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash, 0); - $hash->{hasCC1101} = 1 if ($ver =~ m/cc1101/); + $hash->{cc1101_available} = 1 if ($ver =~ m/cc1101/); } } else { - delete($hash->{getcmd}); + delete($hash->{ucCmd}); $hash->{initretry} ++; #InternalTimer(gettimeofday()+1, "SIGNALduino_StartInit", $hash, 0); SIGNALduino_StartInit($hash); @@ -1179,8 +1414,8 @@ sub SIGNALduino_CheckCmdResp($) { # Check if the 1% limit is reached and trigger notifies sub SIGNALduino_XmitLimitCheck($$) { my ($hash,$fn) = @_; - - return if ($fn !~ m/^(is|SR).*/); + + return if ($fn !~ m/^(is|S[RCM]).*/); my $now = time(); @@ -1228,7 +1463,7 @@ sub SIGNALduino_Write($$$) { $msg = SIGNALduino_PreparingSend_FS20_FHT(73, 12, $msg); } $hash->{logMethod}->($name, 5, "$name: Write, sending via Set $fn $msg"); - + SIGNALduino_Set($hash,$name,$fn,$msg); } @@ -1236,38 +1471,51 @@ sub SIGNALduino_Write($$$) { sub SIGNALduino_AddSendQueue($$) { my ($hash, $msg) = @_; my $name = $hash->{NAME}; - + push(@{$hash->{QUEUE}}, $msg); - + #SIGNALduino_Log3 $hash , 5, Dumper($hash->{QUEUE}); - + $hash->{logMethod}->($hash, 5,"$name: AddSendQueue, " . $hash->{NAME} . ": $msg (" . @{$hash->{QUEUE}} . ")"); - InternalTimer(gettimeofday() + 0.1, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name") if (@{$hash->{QUEUE}} == 1 && $hash->{sendworking} == 0); + InternalTimer(gettimeofday() + 0.1, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name") if (scalar @{$hash->{QUEUE}} == 1 && InternalVal($name,"sendworking",0) == 0); } ############################### sub SIGNALduino_SendFromQueue($$) { my ($hash, $msg) = @_; my $name = $hash->{NAME}; + + $hash->{logMethod}->($name, 4, "$name: SendFromQueue, called"); if($msg ne "") { SIGNALduino_XmitLimitCheck($hash,$msg); #DevIo_SimpleWrite($hash, $msg . "\n", 2); $hash->{sendworking} = 1; SIGNALduino_SimpleWrite($hash,$msg); - if ($msg =~ m/^S(R|C|M);/) { - $hash->{getcmd}->{cmd} = 'sendraw'; - $hash->{logMethod}->($name, 4, "$name: SendFromQueue, msg=$msg"); # zu testen der Queue, kann wenn es funktioniert auskommentiert werden - } - elsif ($msg eq "C99") { - $hash->{getcmd}->{cmd} = 'ccregAll'; + if ($msg =~ m/^S[RCM];/) { + $hash->{ucCmd}->{cmd} = 'sendraw'; + $hash->{ucCmd}->{timenow} = time(); + $hash->{ucCmd}->{responseSub} = \&SIGNALduino_CheckSendRawResponse; + $hash->{logMethod}->($name, 4, "$name: SendFromQueue, msg=$msg"); # zu testen der Queue, kann wenn es funktioniert auskommentiert werden + } elsif ($msg =~ "^e") { # Werkseinstellungen + SIGNALduino_Get($hash,$name,"ccconf"); + SIGNALduino_Get($hash,$name,"ccpatable"); + } elsif ($msg =~ "^W(?:0F|10|11|1D|12|1F)") { # SetFreq, setrAmpl, Set_bWidth, SetSens + SIGNALduino_Get($hash,$name,"ccconf"); + } elsif ($msg =~ "^x") { # patable + SIGNALduino_Get($hash,$name,"ccpatable"); } +# elsif ($msg eq "C99") { +# $hash->{ucCmd}->{cmd} = 'ccregAll'; +# $hash->{ucCmd}->{responseSub} = \&SIGNALduino_CheckCcregResponse; +# +# } } ############## # Write the next buffer not earlier than 0.23 seconds # else it will be sent too early by the SIGNALduino, resulting in a collision, or may the last command is not finished - - if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') { + + if (defined($hash->{ucCmd}->{cmd}) && $hash->{ucCmd}->{cmd} eq 'sendraw') { InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_TIMEOUT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name"); } else { InternalTimer(gettimeofday() + SDUINO_WRITEQUEUE_NEXT, "SIGNALduino_HandleWriteQueue", "HandleWriteQueue:$name"); @@ -1279,16 +1527,17 @@ sub SIGNALduino_HandleWriteQueue($) { my($param) = @_; my(undef,$name) = split(':', $param); my $hash = $defs{$name}; - + #my @arr = @{$hash->{QUEUE}}; - + + $hash->{logMethod}->($name, 4, "$name: HandleWriteQueue, called"); $hash->{sendworking} = 0; # es wurde gesendet - - if (defined($hash->{getcmd}->{cmd}) && $hash->{getcmd}->{cmd} eq 'sendraw') { + + if (exists($hash->{ucCmd}) && exists($hash->{ucCmd}->{cmd}) && $hash->{ucCmd}->{cmd} eq 'sendraw') { $hash->{logMethod}->($name, 4, "$name: HandleWriteQueue, sendraw no answer (timeout)"); - delete($hash->{getcmd}); + delete($hash->{ucCmd}); } - + if(exists($hash->{QUEUE}) && @{$hash->{QUEUE}}) { my $msg= shift(@{$hash->{QUEUE}}); @@ -1321,7 +1570,7 @@ sub SIGNALduino_Read($) { my $rmsg; ($rmsg,$SIGNALduinodata) = split("\n", $SIGNALduinodata, 2); $rmsg =~ s/\r//; - + if ($rmsg =~ m/^\002(M(s|u|o);.*;)\003/) { $rmsg =~ s/^\002//; # \002 am Anfang entfernen my @msg_parts = split(";",$rmsg); @@ -1333,7 +1582,7 @@ sub SIGNALduino_Read($) { my $part = ""; my $partD; $hash->{logMethod}->($name, 5, "$name: Read, RAW rmsg: $rmsg"); - + foreach my $msgPart (@msg_parts) { next if ($msgPart eq ""); $m0 = substr($msgPart,0,1); @@ -1380,7 +1629,7 @@ sub SIGNALduino_Read($) { elsif ($m0 eq "o" || $m0 eq "m") { $part .= "$m0$m1;"; } - elsif ($m1 =~ m/^[0-9A-Z]{1,2}$/) { # bei 1 oder 2 Hex Ziffern nach Dez wandeln + elsif ($m1 =~ m/^[0-9A-Z]{1,2}$/) { # bei 1 oder 2 Hex Ziffern nach Dez wandeln $part .= "$m0=" . hex($m1) . ";"; } elsif ($m0 =~m/[0-9a-zA-Z]/) { @@ -1398,60 +1647,31 @@ sub SIGNALduino_Read($) { $hash->{logMethod}->($name, 4, "$name: Read, msg: $rmsg"); } - if ( $rmsg && !SIGNALduino_Parse($hash, $hash, $name, $rmsg) && defined($hash->{getcmd}) && defined($hash->{getcmd}->{cmd})) + if ( $rmsg && !SIGNALduino_Parse($hash, $hash, $name, $rmsg) && exists($hash->{ucCmd}) && defined($hash->{ucCmd}->{cmd})) { - my $regexp; - if ($hash->{getcmd}->{cmd} eq 'sendraw') { # todo: pruefen wieso die regexp nicht im %gets hinterlegt ist. Das könnte in paar Zeilen code sparen - $regexp = '^S(?:R|C|M);.'; - } - elsif ($hash->{getcmd}->{cmd} eq 'ccregAll') { - $regexp = '^ccreg 00:'; - } - elsif ($hash->{getcmd}->{cmd} eq 'bWidth') { - $regexp = '^C.* = .*'; - } - else { - $regexp = $gets{$hash->{getcmd}->{cmd}}[1]; - } - if(!defined($regexp) || $rmsg =~ m/$regexp/) { - if (defined($hash->{keepalive})) { + my $regexp = exists($gets{$hash->{ucCmd}->{cmd}}) && exists($gets{$hash->{ucCmd}->{cmd}}[4]) ? $gets{$hash->{ucCmd}->{cmd}}[4] : ".*"; + if (exists($hash->{ucCmd}->{responseSub}) && ref $hash->{ucCmd}->{responseSub} eq "CODE") { + $hash->{logMethod}->($name, 5, "$name: Read, msg: regexp=$regexp cmd=$hash->{ucCmd}->{cmd} msg=$rmsg"); + my $returnMessage ; + my $event; + if (!exists($gets{$hash->{ucCmd}->{cmd}}) || !exists($gets{$hash->{ucCmd}->{cmd}}[4]) || $rmsg =~ /$regexp/) + { + ($returnMessage,$event) = $hash->{ucCmd}->{responseSub}->($hash,$rmsg) ; + readingsSingleUpdate($hash, $hash->{ucCmd}->{cmd}, $returnMessage, $event) if (defined($returnMessage) && defined($event)); + if (exists($hash->{ucCmd}->{asyncOut})) { + $hash->{logMethod}->($name, 5, "$name: Read, try asyncOutput of message $returnMessage"); + my $ao = asyncOutput( $hash->{ucCmd}->{asyncOut}, $hash->{ucCmd}->{cmd}.": " . $returnMessage ) if (defined($returnMessage)); + $hash->{logMethod}->($name, 5, "$name: Read, asyncOutput failed $ao") if ($ao); + } + delete($hash->{ucCmd}); + } + + if (exists($hash->{keepalive})) { $hash->{keepalive}{ok} = 1; $hash->{keepalive}{retry} = 0; } - $hash->{logMethod}->($name, 5, "$name: Read, msg: regexp=$regexp cmd=$hash->{getcmd}->{cmd} msg=$rmsg"); - - if ($hash->{getcmd}->{cmd} eq 'version') { # todo prüfen ob der code nicht in die %gets tabelle verschoben werden kann - my $msg_start = index($rmsg, 'V 3.'); - if ($msg_start > 0) { - $rmsg = substr($rmsg, $msg_start); - $hash->{logMethod}->($name, 4, "$name: Read, cut chars at begin. msgstart = $msg_start msg = $rmsg"); - } - $hash->{version} = $rmsg; - if (defined($hash->{DevState}) && $hash->{DevState} eq 'waitInit') { - RemoveInternalTimer($hash); - SIGNALduino_CheckCmdResp($hash); - } - } - if ($hash->{getcmd}->{cmd} eq 'sendraw') { - # zu testen der sendeQueue, kann wenn es funktioniert auf verbose 5 - $hash->{logMethod}->($name, 4, "$name: Read, sendraw answer: $rmsg"); - delete($hash->{getcmd}); - RemoveInternalTimer("HandleWriteQueue:$name"); - SIGNALduino_HandleWriteQueue("x:$name"); - } - else { - $rmsg = SIGNALduino_parseResponse($hash,$hash->{getcmd}->{cmd},$rmsg); - if (defined($hash->{getcmd}) && $hash->{getcmd}->{cmd} ne 'ccregAll') { - readingsSingleUpdate($hash, $hash->{getcmd}->{cmd}, $rmsg, 0); - } - if (defined($hash->{getcmd}->{asyncOut})) { - #SIGNALduino_Log3 $name, 4, "$name: Read, msg: asyncOutput"; - my $ao = asyncOutput( $hash->{getcmd}->{asyncOut}, $hash->{getcmd}->{cmd}.": " . $rmsg ); - } - delete($hash->{getcmd}); - } } else { - $hash->{logMethod}->($name, 4, "$name: Read, msg: Received answer ($rmsg) for ". $hash->{getcmd}->{cmd}." does not match $regexp"); + $hash->{logMethod}->($name, 4, "$name: Read, msg: Received answer ($rmsg) for ". $hash->{ucCmd}->{cmd}." does not match $regexp / coderef"); } } } @@ -1462,12 +1682,12 @@ sub SIGNALduino_Read($) { sub SIGNALduino_KeepAlive($){ my ($hash) = @_; my $name = $hash->{NAME}; - + return if ($hash->{DevState} eq 'disconnected'); - + #SIGNALduino_Log3 $name,4 , "$name: KeepAliveOk, " . $hash->{keepalive}{ok}; if (!$hash->{keepalive}{ok}) { - delete($hash->{getcmd}); + delete($hash->{ucCmd}); if ($hash->{keepalive}{retry} >= SDUINO_KEEPALIVE_MAXRETRY) { $hash->{logMethod}->($name,3 , "$name: KeepAlive, not ok, retry count reached. Reset"); $hash->{DevState} = 'INACTIVE'; @@ -1481,16 +1701,17 @@ sub SIGNALduino_KeepAlive($){ $logLevel = 4; } $hash->{logMethod}->($name, $logLevel, "$name: KeepAlive, not ok, retry = " . $hash->{keepalive}{retry} . " -> get ping"); - $hash->{getcmd}->{cmd} = "ping"; + $hash->{ucCmd}->{cmd} = "ping"; + $hash->{ucCmd}->{timenow} = time(); + $hash->{ucCmd}->{responseSub} = \&SIGNALduino_GetResponseUpdateReading; SIGNALduino_AddSendQueue($hash, "P"); - #SIGNALduino_SimpleWrite($hash, "P"); } } else { $hash->{logMethod}->($name,4 , "$name: KeepAlive, ok, retry = " . $hash->{keepalive}{retry}); } $hash->{keepalive}{ok} = 0; - + InternalTimer(gettimeofday() + SDUINO_KEEPALIVE_TIMEOUT, "SIGNALduino_KeepAlive", $hash); } @@ -1500,7 +1721,7 @@ sub SIGNALduino_KeepAlive($){ ############################### ## Parses a HTTP Response for example for flash via http download sub SIGNALduino_ParseHttpResponse { - + my ($param, $err, $data) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; @@ -1511,29 +1732,29 @@ sub SIGNALduino_ParseHttpResponse { } elsif($param->{code} eq "200" && $data ne "") # wenn die Abfrage erfolgreich war ($data enthaelt die Ergebnisdaten des HTTP Aufrufes) { - + $hash->{logMethod}->($name, 3, "$name: ParseHttpResponse, url ".$param->{url}." returned: ".length($data)." bytes Data"); # Eintrag fuers Log - + if ($param->{command} eq "flash") { my $filename; - + if ($param->{httpheader} =~ /Content-Disposition: attachment;.?filename=\"?([-+.\w]+)?\"?/) - { + { $filename = $1; } else { # Filename via path if not specifyied via Content-Disposition - ($filename = $param->{path}) =~s/.*\///; + $param->{path} =~ /\/([-+.\w]+)$/; #(?:[^\/][\d\w\.]+)+$ \/([-+.\w]+)$ + $filename = $1; } - $hash->{logMethod}->($name, 3, "$name: ParseHttpResponse, Downloaded $filename firmware from ".$param->{host}); $hash->{logMethod}->($name, 5, "$name: ParseHttpResponse, Header = ".$param->{httpheader}); - - + + $filename = "FHEM/firmware/" . $filename; open(my $file, ">", $filename) or die $!; print $file $data; close $file; - + # Den Flash Befehl mit der soebene heruntergeladenen Datei ausfuehren #SIGNALduino_Log3 $name, 3, "$name: ParseHttpResponse, calling set ".$param->{command}." $filename"; # Eintrag fuers Log @@ -1541,7 +1762,7 @@ sub SIGNALduino_ParseHttpResponse { if (defined($set_return)) { $hash->{logMethod}->($name ,3, "$name: ParseHttpResponse, Error while flashing: $set_return"); - } + } } } else { $hash->{logMethod}->($name, 3, "$name: ParseHttpResponse, undefined error while requesting ".$param->{url}." - $err - code=".$param->{code}); # Eintrag fuers Log @@ -1553,7 +1774,7 @@ sub SIGNALduino_splitMsg { my $txt = shift; my $delim = shift; my @msg_parts = split(/$delim/,$txt); - + return @msg_parts; } @@ -1589,7 +1810,7 @@ sub SIGNALduino_FillPatternLookupTable { ############################### #=item SIGNALduino_PatternExists() # This functons, needs reference to $hash, @array of values to search and %patternList where to find the matches. -# +# # Will return -1 if pattern is not found or a string, containing the indexes which are in tolerance and have the smallest gap to what we searched # =cut @@ -1598,44 +1819,44 @@ sub SIGNALduino_FillPatternLookupTable { sub SIGNALduino_PatternExists { my ($hash,$search,$patternList,$data) = @_; #my %patternList=$arg3; - #Debug "plist: ".Dumper($patternList) if($debug); + #Debug "plist: ".Dumper($patternList) if($debug); #Debug "searchlist: ".Dumper($search) if($debug); my $searchpattern; - my $valid=1; + my $valid=1; my @pstr; my $debug = AttrVal($hash->{NAME},"debug",0); - + my $i=0; - + my $maxcol=0; - - foreach $searchpattern (@{$search}) # z.B. [1, -4] + + foreach $searchpattern (@{$search}) # z.B. [1, -4] { #my $patt_id; # Calculate tolernace for search #my $tol=abs(abs($searchpattern)>=2 ?$searchpattern*0.3:$searchpattern*1.5); my $tol=abs(abs($searchpattern)>3 ? abs($searchpattern)>16 ? $searchpattern*0.18 : $searchpattern*0.3 : 1); #tol is minimum 1 or higer, depending on our searched pulselengh - - Debug "tol: looking for ($searchpattern +- $tol)" if($debug); - + + Debug "tol: looking for ($searchpattern +- $tol)" if($debug); + my %pattern_gap ; #= {}; # Find and store the gap of every pattern, which is in tolerance %pattern_gap = map { $_ => abs($patternList->{$_}-$searchpattern) } grep { abs($patternList->{$_}-$searchpattern) <= $tol} (keys %$patternList); - if (scalar keys %pattern_gap > 0) + if (scalar keys %pattern_gap > 0) { Debug "index => gap in tol (+- $tol) of pulse ($searchpattern) : ".Dumper(\%pattern_gap) if($debug); # Extract fist pattern, which is nearst to our searched value my @closestidx = (sort {$pattern_gap{$a} <=> $pattern_gap{$b}} keys %pattern_gap); - + my $idxstr=""; my $r=0; - - while (my ($item) = splice(@closestidx, 0, 1)) + + while (my ($item) = splice(@closestidx, 0, 1)) { - $pstr[$i][$r]=$item; + $pstr[$i][$r]=$item; $r++; Debug "closest pattern has index: $item" if($debug); } @@ -1643,14 +1864,14 @@ sub SIGNALduino_PatternExists { } else { # search is not found, return -1 return -1; - last; + last; } $i++; #return ($valid ? $pstr : -1); # return $pstr if $valid or -1 - + #foreach $patt_id (keys %$patternList) { - #Debug "$patt_id. chk ->intol $patternList->{$patt_id} $searchpattern $tol"; + #Debug "$patt_id. chk ->intol $patternList->{$patt_id} $searchpattern $tol"; #$valid = SIGNALduino_inTol($patternList->{$patt_id}, $searchpattern, $tol); #if ( $valid) #one pulse found in tolerance, search next one #{ @@ -1663,21 +1884,21 @@ sub SIGNALduino_PatternExists { #last if (!$valid); ## Exit loop if a complete iteration has not found anything } my @results = (''); - + foreach my $subarray (@pstr) { @results = map {my $res = $_; map $res.$_, @$subarray } @results; } - + foreach my $search (@results) { Debug "looking for substr $search" if($debug); - + return $search if (index( ${$data}, $search) >= 0); } - + return -1; - + #return ($valid ? @results : -1); # return @pstr if $valid or -1 } @@ -1686,20 +1907,20 @@ sub SIGNALduino_MatchSignalPattern($\@\%\@$){ my ( $hash, $signalpattern, $patternList, $data_array, $idx) = @_; my $name = $hash->{NAME}; - #print Dumper($patternList); - #print Dumper($idx); - #Debug Dumper($signalpattern) if ($debug); + #print Dumper($patternList); + #print Dumper($idx); + #Debug Dumper($signalpattern) if ($debug); my $tol="0.2"; # Tolerance factor my $found=0; my $debug = AttrVal($hash->{NAME},"debug",0); - + foreach ( @{$signalpattern} ) { - #Debug " $idx check: ".$patternList->{$data_array->[$idx]}." == ".$_; - Debug "$name: idx: $idx check: abs(". $patternList->{$data_array->[$idx]}." - ".$_.") > ". ceil(abs($patternList->{$data_array->[$idx]}*$tol)) if ($debug); - + #Debug " $idx check: ".$patternList->{$data_array->[$idx]}." == ".$_; + Debug "$name: idx: $idx check: abs(". $patternList->{$data_array->[$idx]}." - ".$_.") > ". ceil(abs($patternList->{$data_array->[$idx]}*$tol)) if ($debug); + #print "\n";; - #if ($patternList->{$data_array->[$idx]} ne $_ ) + #if ($patternList->{$data_array->[$idx]} ne $_ ) ### Nachkommastelle von ceil!!! if (!defined( $patternList->{$data_array->[$idx]})){ Debug "$name: Error index ($idx) does not exist!!" if ($debug); @@ -1717,7 +1938,7 @@ sub SIGNALduino_MatchSignalPattern($\@\%\@$){ { return $idx; ## Return new Index Position } - + } ############################### @@ -1750,11 +1971,11 @@ sub SIGNALduino_Split_Message($$) { my $clockabs; my $mcbitnum; my $rssi; - + my @msg_parts = SIGNALduino_splitMsg($rmsg,';'); ## Split message parts by ";" my %ret; my $debug = AttrVal($name,"debug",0); - + foreach (@msg_parts) { #Debug "$name: checking msg part:( $_ )" if ($debug); @@ -1766,17 +1987,17 @@ sub SIGNALduino_Split_Message($$) { } elsif ($_ =~ m/^P\d=-?\d{2,}/ or $_ =~ m/^[SL][LH]=-?\d{2,}/) #### Extract Pattern List from array { - $_ =~ s/^P+//; - $_ =~ s/^P\d//; + $_ =~ s/^P+//; + $_ =~ s/^P\d//; my @pattern = split(/=/,$_); - + $patternList{$pattern[0]} = $pattern[1]; Debug "$name: extracted pattern @pattern \n" if ($debug); } elsif($_ =~ m/D=\d+/ or $_ =~ m/^D=[A-F0-9]+/) #### Message from array { - $_ =~ s/D=//; + $_ =~ s/D=//; $rawData = $_ ; Debug "$name: extracted data $rawData\n" if ($debug); $ret{rawData} = $rawData; @@ -1803,10 +2024,10 @@ sub SIGNALduino_Split_Message($$) { Debug "$name: extracted number of $mcbitnum bits\n" if ($debug);; $ret{mcbitnum} = $mcbitnum; } - + elsif($_ =~ m/^C=\d+/) #### Message from array { - $_ =~ s/C=//; + $_ =~ s/C=//; $clockabs = $_ ; Debug "$name: extracted absolute clock $clockabs \n" if ($debug); $ret{clockabs} = $clockabs; @@ -1822,7 +2043,7 @@ sub SIGNALduino_Split_Message($$) { } #print "$_\n"; } - $ret{pattern} = {%patternList}; + $ret{pattern} = {%patternList}; return %ret; } @@ -1831,15 +2052,15 @@ sub SIGNALduino_Split_Message($$) { sub SIGNALduno_Dispatch($$$$$) { my ($hash, $rmsg, $dmsg, $rssi, $id) = @_; my $name = $hash->{NAME}; - + if (!defined($dmsg)) { $hash->{logMethod}->($name, 5, "$name: Dispatch, dmsg is undef. Skipping dispatch call"); return; } - + #SIGNALduino_Log3 $name, 5, "$name: Dispatch, DMSG: $dmsg"; - + my $DMSGgleich = 1; if ($dmsg eq $hash->{LASTDMSG}) { $hash->{logMethod}->($name, SDUINO_DISPATCH_VERBOSE, "$name: Dispatch, $dmsg, test gleich"); @@ -1857,7 +2078,7 @@ sub SIGNALduno_Dispatch($$$$$) { if ($DMSGgleich) { #Dispatch if dispatchequals is provided in protocol definition or only if $dmsg is different from last $dmsg, or if 2 seconds are between transmits - if ( (SIGNALduino_getProtoProp($id,'dispatchequals',0) eq 'true') || ($hash->{DMSG} ne $dmsg) || ($hash->{TIME}+2 < time() ) ) { + if ( (SIGNALduino_getProtoProp($id,'dispatchequals',0) eq 'true') || ($hash->{DMSG} ne $dmsg) || ($hash->{TIME}+2 < time() ) ) { $hash->{MSGCNT}++; $hash->{TIME} = time(); $hash->{DMSG} = $dmsg; @@ -1868,7 +2089,7 @@ sub SIGNALduno_Dispatch($$$$$) { return if (substr($dmsg,0,1) eq 'U'); # Fuer $dmsg die mit U anfangen ist kein Dispatch notwendig, da es dafuer kein Modul gibt klein u wird dagegen dispatcht } #readingsSingleUpdate($hash, "state", $hash->{READINGS}{state}{VAL}, $event); - + $hash->{RAWMSG} = $rmsg; my %addvals = ( DMSG => $dmsg, @@ -1887,8 +2108,8 @@ sub SIGNALduno_Dispatch($$$$$) { } $dmsg = lc($dmsg) if ($id eq '74' or $id eq '74.1'); # 10_FS20.pm accepted only lower case hex $hash->{logMethod}->($name, SDUINO_DISPATCH_VERBOSE, "$name: Dispatch, $dmsg, $rssi dispatch"); - Dispatch($hash, $dmsg, \%addvals); ## Dispatch to other Modules - + Dispatch($hash, $dmsg, \%addvals); ## Dispatch to other Modules + } else { $hash->{logMethod}->($name, 4, "$name: Dispatch, $dmsg, Dropped due to short time or equal msg"); } @@ -1896,12 +2117,12 @@ sub SIGNALduno_Dispatch($$$$$) { } ############################### -# param #1 is name of definition +# param #1 is name of definition # param #2 is protocol id # param #3 is dispatched message to check against # # returns 1 if message matches modulematch + development attribute/whitelistIDs -# returns 0 if message does not match modulematch +# returns 0 if message does not match modulematch # return -1 if message is not activated via whitelistIDs but has developID=m flag sub SIGNALduino_moduleMatch { my $name = shift; @@ -1909,7 +2130,7 @@ sub SIGNALduino_moduleMatch { my $dmsg = shift; my $debug = AttrVal($name,"debug",0); my $modMatchRegex=SIGNALduino_getProtoProp($id,"modulematch",undef); - + if (!defined($modMatchRegex) || $dmsg =~ m/$modMatchRegex/) { Debug "$name: modmatch passed for: $dmsg" if ($debug); my $developID = SIGNALduino_getProtoProp($id,"developId",""); @@ -1919,7 +2140,7 @@ sub SIGNALduino_moduleMatch { return -1; } - return 1; # return 1 da modulematch gefunden wurde + return 1; # return 1 da modulematch gefunden wurde } return 0; } @@ -1928,35 +2149,35 @@ sub SIGNALduino_moduleMatch { sub SIGNALduino_Parse_MS($$$$%) { my ($hash, $iohash, $name, $rmsg,%msg_parts) = @_; - my $syncidx=$msg_parts{syncidx}; - my $clockidx=$msg_parts{clockidx}; + my $syncidx=$msg_parts{syncidx}; + my $clockidx=$msg_parts{clockidx}; my $rssi=$msg_parts{rssi}; my $rawData=$msg_parts{rawData}; my %patternList; my $rssiStr= ""; - + if (defined($rssi)) { $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm $rssiStr= " RSSI = $rssi" } - + #Debug "Message splitted:"; #Debug Dumper(\@msg_parts); my $debug = AttrVal($iohash->{NAME},"debug",0); - + if (defined($clockidx) and defined($syncidx)) { - + ## Make a lookup table for our pattern index ids #Debug "List of pattern:"; my $clockabs= $msg_parts{pattern}{$msg_parts{clockidx}}; - return undef if ($clockabs == 0); + return undef if ($clockabs == 0); $patternList{$_} = round($msg_parts{pattern}{$_}/$clockabs,1) for keys %{$msg_parts{pattern}}; - - - #Debug Dumper(\%patternList); + + + #Debug Dumper(\%patternList); #my $syncfact = $patternList{$syncidx}/$patternList{$clockidx}; #$syncfact=$patternList{$syncidx}; @@ -1968,16 +2189,16 @@ sub SIGNALduino_Parse_MS($$$$%) { ## Find matching protocols my $id; my $message_dispatched=0; - + IDLOOP: foreach $id (@{$hash->{msIdList}}) { - + Debug "Testing against Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($debug); # Check Clock if is it in range if ($ProtocolListSIGNALduino{$id}{clockabs} > 0) { if (!SIGNALduino_inTol($ProtocolListSIGNALduino{$id}{clockabs},$clockabs,$clockabs*0.30)) { - Debug "protocClock=$ProtocolListSIGNALduino{$id}{clockabs}, msgClock=$clockabs is not in tol=" . $clockabs*0.30 if ($debug); + Debug "protocClock=$ProtocolListSIGNALduino{$id}{clockabs}, msgClock=$clockabs is not in tol=" . $clockabs*0.30 if ($debug); next; } elsif ($debug) { Debug "protocClock=$ProtocolListSIGNALduino{$id}{clockabs}, msgClock=$clockabs is in tol=" . $clockabs*0.30; @@ -1985,7 +2206,7 @@ sub SIGNALduino_Parse_MS($$$$%) { } Debug "Searching in patternList: ".Dumper(\%patternList) if($debug); - + my %patternLookupHash=(); my %endPatternLookupHash=(); my $signal_width= @{$ProtocolListSIGNALduino{$id}{one}}; @@ -1993,13 +2214,13 @@ sub SIGNALduino_Parse_MS($$$$%) { my $message_start; foreach my $key (qw(sync one zero float) ) { next if (!exists($ProtocolListSIGNALduino{$id}{$key})); - + if (!SIGNALduino_FillPatternLookupTable($hash,\@{$ProtocolListSIGNALduino{$id}{$key}},\$symbol_map{$key},\%patternList,\$rawData,\%patternLookupHash,\%endPatternLookupHash,\$return_text)) { Debug sprintf("%s pattern not found",$key) if ($debug); next IDLOOP if ($key ne "float") ; } - + if ($key eq "sync") { $message_start =index($rawData,$return_text)+length($return_text); @@ -2014,7 +2235,7 @@ sub SIGNALduino_Parse_MS($$$$%) { Debug sprintf("Found matched %s with indexes: (%s)",$key,$return_text) if ($debug); } next if (scalar keys %patternLookupHash == 0); # Keine Eingträge im patternLookupHash - + $hash->{logMethod}->($name, 4, "$name: Parse_MS, Matched MS Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}"); my @bit_msg; # array to store decoded signal bits @@ -2043,10 +2264,10 @@ sub SIGNALduino_Parse_MS($$$$%) { last; } } - - + + Debug "$name: decoded message raw (@bit_msg), ".@bit_msg." bits\n" if ($debug); - + #Check converted message against lengths my ($rcode, $rtxt) = SIGNALduino_TestLength(undef,$id,scalar @bit_msg,undef); if (!$rcode) @@ -2055,7 +2276,7 @@ sub SIGNALduino_Parse_MS($$$$%) { next; } my $padwith = lib::SD_Protocols::checkProperty($id,'paddingbits',4); - + my $i=0; while (scalar @bit_msg % $padwith > 0) ## will pad up full nibbles per default or full byte if specified in protocol { @@ -2063,43 +2284,43 @@ sub SIGNALduino_Parse_MS($$$$%) { $i++; } Debug "$name padded $i bits to bit_msg array" if ($debug); - + if ($i == 0) { $hash->{logMethod}->($name, 5, "$name: Parse_MS, dispatching bits: @bit_msg"); } else { $hash->{logMethod}->($name, 5, "$name: Parse_MS, dispatching bits: @bit_msg with $i Paddingbits 0"); } - + my $evalcheck = (SIGNALduino_getProtoProp($id,"developId","") =~ 'p') ? 1 : undef; ($rcode,my @retvalue) = SIGNALduino_callsub('postDemodulation',$ProtocolListSIGNALduino{$id}{postDemodulation},$evalcheck,$name,@bit_msg); next if ($rcode < 1 ); #SIGNALduino_Log3 $name, 5, "$name: Parse_MS, postdemodulation value @retvalue"; - + @bit_msg = @retvalue; undef(@retvalue); undef($rcode); - + my $dmsg = SIGNALduino_b2h(join "", @bit_msg); my $postamble = $ProtocolListSIGNALduino{$id}{postamble}; $dmsg = "$dmsg".$postamble if (defined($postamble)); $dmsg = "$ProtocolListSIGNALduino{$id}{preamble}"."$dmsg" if (defined($ProtocolListSIGNALduino{$id}{preamble})); - - + + #my ($rcode,@retvalue) = SIGNALduino_callsub('preDispatchfunc',$ProtocolListSIGNALduino{$id}{preDispatchfunc},$name,$dmsg); #next if (!$rcode); #$dmsg = @retvalue; #undef(@retvalue); undef($rcode); - + if ( SIGNALduino_moduleMatch($name,$id,$dmsg) == 1) { $message_dispatched++; $hash->{logMethod}->($name, 4, "$name: Parse_MS, Decoded matched MS Protocol id $id dmsg $dmsg length " . scalar @bit_msg . " $rssiStr"); SIGNALduno_Dispatch($hash,$rmsg,$dmsg,$rssi,$id); - } - + } + } - + return 0 if (!$message_dispatched); - + return $message_dispatched; } @@ -2119,14 +2340,14 @@ sub SIGNALduino_padbits(\@$) { ############################### #=item SIGNALduino_getProtoProp() #This functons, will return a value from the Protocolist and check if the key exists and a value is defined optional you can specify a optional default value that will be reurned -# +# # returns "" if the var is not defined # =cut # $id, $propertyname, sub SIGNALduino_getProtoProp { my ($id,$propNameLst,$default) = @_; - + #my $id = shift; #my $propNameLst = shift; return $ProtocolListSIGNALduino{$id}{$propNameLst} if exists($ProtocolListSIGNALduino{$id}{$propNameLst}) && defined($ProtocolListSIGNALduino{$id}{$propNameLst}); @@ -2146,31 +2367,31 @@ sub SIGNALduino_Parse_MU($$$$@) { my $message_dispatched=0; my $debug = AttrVal($iohash->{NAME},"debug",0); my $rssiStr= ""; - + if (defined($rssi)) { $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm $rssiStr= " RSSI = $rssi" } - + Debug "$name: processing unsynced message\n" if ($debug); my $clockabs = 1; #Clock will be fetched from Protocol if possible #$patternListRaw{$_} = floor($msg_parts{pattern}{$_}/$clockabs) for keys $msg_parts{pattern}; $patternListRaw{$_} = $msg_parts{pattern}{$_} for keys %{$msg_parts{pattern}}; - + if (defined($clockidx)) { - + ## Make a lookup table for our pattern index ids - #Debug "List of pattern:"; #Debug Dumper(\%patternList); + #Debug "List of pattern:"; #Debug Dumper(\%patternList); ## Find matching protocols my $id; - + IDLOOP: foreach $id (@{$hash->{muIdList}}) { - + $clockabs= $ProtocolListSIGNALduino{$id}{clockabs}; my %patternList; $rawData=$msg_parts{rawData}; @@ -2181,32 +2402,32 @@ sub SIGNALduino_Parse_MU($$$$@) { { $hash->{logMethod}->($name, 5, "$name: Parse_MU, Error: Unknown filtermethod=$method. Please define it in file $0"); next; - } else { + } else { $hash->{logMethod}->($name, 5, "$name: Parse_MU, for MU Protocol id $id, applying filterfunc $method"); no strict "refs"; - (my $count_changes,$rawData,my %patternListRaw_tmp) = $method->($name,$id,$rawData,%patternListRaw); + (my $count_changes,$rawData,my %patternListRaw_tmp) = $method->($name,$id,$rawData,%patternListRaw); use strict "refs"; - %patternList = map { $_ => round($patternListRaw_tmp{$_}/$clockabs,1) } keys %patternListRaw_tmp; + %patternList = map { $_ => round($patternListRaw_tmp{$_}/$clockabs,1) } keys %patternListRaw_tmp; } } else { - %patternList = map { $_ => round($patternListRaw{$_}/$clockabs,1) } keys %patternListRaw; + %patternList = map { $_ => round($patternListRaw{$_}/$clockabs,1) } keys %patternListRaw; } - - + + Debug "Testing against Protocol id $id -> $ProtocolListSIGNALduino{$id}{name}" if ($debug); Debug "Searching in patternList: ".Dumper(\%patternList) if($debug); my $startStr=""; # Default match if there is no start pattern available my $message_start=0 ; my $startLogStr=""; - + if (exists($ProtocolListSIGNALduino{$id}{start}) && defined($ProtocolListSIGNALduino{$id}{start}) && ref($ProtocolListSIGNALduino{$id}{start}) eq 'ARRAY') # wenn start definiert ist, dann startStr ermitteln und in rawData suchen und in der rawData alles bis zum startStr abschneiden { Debug "msgStartLst: ".Dumper(\@{$ProtocolListSIGNALduino{$id}{start}}) if ($debug); - - + + if ( ($startStr=SIGNALduino_PatternExists($hash,\@{$ProtocolListSIGNALduino{$id}{start}},\%patternList,\$rawData)) eq -1) { $hash->{logMethod}->($name, 5, "$name: Parse_MU, start pattern for MU Protocol id $id -> $ProtocolListSIGNALduino{$id}{name} not found, aborting"); @@ -2214,7 +2435,7 @@ sub SIGNALduino_Parse_MU($$$$@) { } Debug "startStr is: $startStr" if ($debug); $message_start = index($rawData, $startStr); - if ( $message_start == -1) + if ( $message_start == -1) { Debug "startStr $startStr not found." if ($debug); next; @@ -2224,10 +2445,10 @@ sub SIGNALduino_Parse_MU($$$$@) { Debug "rawData = $rawData" if ($debug); Debug "startStr $startStr found. Message starts at $message_start" if ($debug); #SIGNALduino_Log3 $name, 5, "$name: Parse_MU, substr: $rawData"; # todo: entfernen - } - + } + } - + my %patternLookupHash=(); my %endPatternLookupHash=(); my $pstr=""; @@ -2236,7 +2457,7 @@ sub SIGNALduino_Parse_MU($$$$@) { my $floatRegex =""; my $return_text=""; my $signalRegex="(?:"; - + foreach my $key (qw(one zero float) ) { next if (!exists($ProtocolListSIGNALduino{$id}{$key})); if (!SIGNALduino_FillPatternLookupTable($hash,\@{$ProtocolListSIGNALduino{$id}{$key}},\$symbol_map{$key},\%patternList,\$rawData,\%patternLookupHash,\%endPatternLookupHash,\$return_text)) @@ -2256,16 +2477,16 @@ sub SIGNALduino_Parse_MU($$$$@) { $signalRegex .= ")"; $hash->{logMethod}->($name, 4, "$name: Parse_MU, Fingerprint for MU Protocol id $id -> $ProtocolListSIGNALduino{$id}{name} matches, trying to demodulate"); - + my $signal_width= @{$ProtocolListSIGNALduino{$id}{one}}; my $length_min = $ProtocolListSIGNALduino{$id}{length_min}; my $length_max = ""; $length_max = $ProtocolListSIGNALduino{$id}{length_max} if (exists($ProtocolListSIGNALduino{$id}{length_max})); - + $signalRegex .= "{$length_min,}"; - + if (exists($ProtocolListSIGNALduino{$id}{reconstructBit})) { - + $signalRegex .= "(?:" . join("|",keys %endPatternLookupHash) . ")?"; } Debug "signalRegex is $signalRegex " if ($debug); @@ -2273,29 +2494,29 @@ sub SIGNALduino_Parse_MU($$$$@) { my $nrRestart=0; my $nrDispatch=0; my $regex="(?:$startStr)($signalRegex)"; - + while ( $rawData =~ m/$regex/g) { my $length_str=""; $nrRestart++; - $hash->{logMethod}->($name, 5, "$name: Parse_MU, part is $1 starts at position $-[0] and ends at ". pos $rawData); - + $hash->{logMethod}->($name, 5, "$name: Parse_MU, part is $1 starts at position $-[0] and ends at ". pos $rawData); + my @pairs = unpack "(a$signal_width)*", $1; - + if (exists($ProtocolListSIGNALduino{$id}{length_max}) && scalar @pairs > $ProtocolListSIGNALduino{$id}{length_max}) # ist die Nachricht zu lang? { $hash->{logMethod}->($name, 5, "$name: Parse_MU, $nrRestart. skip demodulation (length ".scalar @pairs." is to long) at Pos $-[0] regex ($regex)"); next; } - + if ($nrRestart == 1) { - $hash->{logMethod}->($name, 5, "$name: Parse_MU, Starting demodulation ($startLogStr " . "regex: $regex Pos $message_start) length_min_max (".$length_min."..".$length_max.") length=".scalar @pairs); + $hash->{logMethod}->($name, 5, "$name: Parse_MU, Starting demodulation ($startLogStr " . "regex: $regex Pos $message_start) length_min_max (".$length_min."..".$length_max.") length=".scalar @pairs); } else { $hash->{logMethod}->($name, 5, "$name: Parse_MU, $nrRestart. try demodulation$length_str at Pos $-[0]"); } - + my @bit_msg=(); # array to store decoded signal bits - + foreach my $sigStr (@pairs) { if (exists $patternLookupHash{$sigStr}) { @@ -2307,37 +2528,37 @@ sub SIGNALduino_Parse_MU($$$$@) { $hash->{logMethod}->($name, 4, "$name: Parse_MU, last part pair=$sigStr reconstructed, bit=$lastbit"); } } - + Debug "$name: demodulated message raw (@bit_msg), ".@bit_msg." bits\n" if ($debug); my $evalcheck = (SIGNALduino_getProtoProp($id,"developId","") =~ 'p') ? 1 : undef; my ($rcode,@retvalue) = SIGNALduino_callsub('postDemodulation',$ProtocolListSIGNALduino{$id}{postDemodulation},$evalcheck,$name,@bit_msg); - + next if ($rcode < 1 ); @bit_msg = @retvalue; undef(@retvalue); undef($rcode); - - my $dispmode="hex"; + + my $dispmode="hex"; $dispmode="bin" if (SIGNALduino_getProtoProp($id,"dispatchBin",0) == 1 ); - + my $padwith = lib::SD_Protocols::checkProperty($id,'paddingbits',4); while (scalar @bit_msg % $padwith > 0) ## will pad up full nibbles per default or full byte if specified in protocol { push(@bit_msg,'0'); Debug "$name: padding 0 bit to bit_msg array" if ($debug); - } + } my $dmsg = join ("", @bit_msg); my $bit_length=scalar @bit_msg; @bit_msg=(); # clear bit_msg array $dmsg = SIGNALduino_b2h($dmsg) if (SIGNALduino_getProtoProp($id,"dispatchBin",0) == 0 ); - + $dmsg =~ s/^0+// if ( SIGNALduino_getProtoProp($id,"remove_zero",0) ); - + $dmsg=sprintf("%s%s%s",SIGNALduino_getProtoProp($id,"preamble",""),$dmsg,SIGNALduino_getProtoProp($id,"postamble","")); $hash->{logMethod}->($name, 5, "$name: Parse_MU, dispatching $dispmode: $dmsg"); - + if ( SIGNALduino_moduleMatch($name,$id,$dmsg) == 1) { $nrDispatch++; @@ -2347,15 +2568,15 @@ sub SIGNALduino_Parse_MU($$$$@) { { last; } - } + } } $hash->{logMethod}->($name, 5, "$name: Parse_MU, $nrRestart. try, regex ($regex) did not match") if ($nrRestart == 0); $message_dispatched=$message_dispatched+$nrDispatch; } - return $message_dispatched; - + return $message_dispatched; + } } @@ -2375,13 +2596,13 @@ sub SIGNALduino_Parse_MC($$$$@) { if (defined($rssi)) { $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); # todo: passt dies so? habe ich vom 00_cul.pm } - + return undef if (!$clock); #my $protocol=undef; #my %patternListRaw = %msg_parts{patternList}; - + Debug "$name: processing manchester messag len:".length($rawData) if ($debug); - + my $hlen = length($rawData); my $blen; #if (defined($mcbitnum)) { @@ -2390,10 +2611,10 @@ sub SIGNALduino_Parse_MC($$$$@) { $blen = $hlen * 4; #} my $id; - + my $rawDataInverted; ($rawDataInverted = $rawData) =~ tr/0123456789ABCDEF/FEDCBA9876543210/; # Some Manchester Data is inverted - + foreach $id (@{$hash->{mcIdList}}) { #next if ($blen < $ProtocolListSIGNALduino{$id}{length_min} || $blen > $ProtocolListSIGNALduino{$id}{length_max}); @@ -2407,7 +2628,7 @@ sub SIGNALduino_Parse_MC($$$$@) { } else { $hash->{logMethod}->($name, 4, "$name: Parse_MC, Found manchester Protocol id $id clock $clock -> $ProtocolListSIGNALduino{$id}{name}"); } - + my $polarityInvert = 0; if (exists($ProtocolListSIGNALduino{$id}{polarity}) && ($ProtocolListSIGNALduino{$id}{polarity} eq 'invert')) { @@ -2419,14 +2640,14 @@ sub SIGNALduino_Parse_MC($$$$@) { } if ($polarityInvert == 1) { - $bitData= unpack("B$blen", pack("H$hlen", $rawDataInverted)); - + $bitData= unpack("B$blen", pack("H$hlen", $rawDataInverted)); + } else { - $bitData= unpack("B$blen", pack("H$hlen", $rawData)); + $bitData= unpack("B$blen", pack("H$hlen", $rawData)); } Debug "$name: extracted data $bitData (bin)\n" if ($debug); ## Convert Message from hex to bits $hash->{logMethod}->($name, 5, "$name: Parse_MC, extracted data $bitData (bin)"); - + my $method = lib::SD_Protocols::getProperty($id,"method"); if (!exists &$method || !defined &{ $method }) { @@ -2436,7 +2657,7 @@ sub SIGNALduino_Parse_MC($$$$@) { my ($rcode,$res) = $method->($name,$bitData,$id,$mcbitnum); if ($rcode != -1) { $dmsg = $res; - $dmsg=$ProtocolListSIGNALduino{$id}{preamble}.$dmsg if (defined($ProtocolListSIGNALduino{$id}{preamble})); + $dmsg=$ProtocolListSIGNALduino{$id}{preamble}.$dmsg if (defined($ProtocolListSIGNALduino{$id}{preamble})); my $modulematch; if (defined($ProtocolListSIGNALduino{$id}{modulematch})) { $modulematch = $ProtocolListSIGNALduino{$id}{modulematch}; @@ -2464,12 +2685,12 @@ sub SIGNALduino_Parse_MC($$$$@) { } } else { $res="undef" if (!defined($res)); - $hash->{logMethod}->($name, 5, "$name: Parse_MC, protocol does not match return from method: ($res)") ; + $hash->{logMethod}->($name, 5, "$name: Parse_MC, protocol does not match return from method: ($res)") ; } } } - + } return 0 if (!$message_dispatched); return 1; @@ -2480,8 +2701,8 @@ sub SIGNALduino_Parse($$$$@) { my ($hash, $iohash, $name, $rmsg, $initstr) = @_; #print Dumper(\%ProtocolListSIGNALduino); - - + + if (!($rmsg=~ s/^\002(M.;.*;)\003/$1/)) # Check if a Data Message arrived and if it's complete (start & end control char are received) { # cut off start end end character from message for further processing they are not needed $hash->{logMethod}->($name, AttrVal($name,"noMsgVerbose",5), "$name: Parse, noMsg: $rmsg"); @@ -2492,24 +2713,24 @@ sub SIGNALduino_Parse($$$$@) { $hash->{keepalive}{ok} = 1; $hash->{keepalive}{retry} = 0; } - + my $debug = AttrVal($iohash->{NAME},"debug",0); - - + + Debug "$name: incoming message: ($rmsg)\n" if ($debug); - + if (AttrVal($name, "rawmsgEvent", 0)) { DoTrigger($name, "RAWMSG " . $rmsg); } - + my %signal_parts=SIGNALduino_Split_Message($rmsg,$name); ## Split message and save anything in an hash %signal_parts #Debug "raw data ". $signal_parts{rawData}; - - + + my $dispatched; # Message Synced type -> M# - if (@{$hash->{msIdList}} && $rmsg=~ m/^MS;(P\d=-?\d+;){3,8}D=\d+;CP=\d;SP=\d;/) + if (@{$hash->{msIdList}} && $rmsg=~ m/^MS;(P\d=-?\d+;){3,8}D=\d+;CP=\d;SP=\d;/) { $dispatched= SIGNALduino_Parse_MS($hash, $iohash, $name, $rmsg,%signal_parts); } @@ -2519,7 +2740,7 @@ sub SIGNALduino_Parse($$$$@) { $dispatched= SIGNALduino_Parse_MU($hash, $iohash, $name, $rmsg,%signal_parts); } # Manchester encoded Data -> MC - elsif (@{$hash->{mcIdList}} && $rmsg=~ m/^M[cC];.*;/) + elsif (@{$hash->{mcIdList}} && $rmsg=~ m/^M[cC];.*;/) { $dispatched= SIGNALduino_Parse_MC($hash, $iohash, $name, $rmsg,%signal_parts); } @@ -2527,14 +2748,14 @@ sub SIGNALduino_Parse($$$$@) { Debug "$name: unknown Messageformat, aborting\n" if ($debug); return undef; } - + if ( AttrVal($hash->{NAME},"verbose","0") > 4 && !$dispatched) { my $notdisplist; my @lines; if (defined($hash->{unknownmessages})) { - $notdisplist=$hash->{unknownmessages}; + $notdisplist=$hash->{unknownmessages}; @lines = split ('#', $notdisplist); # or whatever } push(@lines,FmtDateTime(time())."-".$rmsg); @@ -2546,7 +2767,7 @@ sub SIGNALduino_Parse($$$$@) { #Todo compare Sync/Clock fact and length of D= if equal, then it's the same protocol! } return $dispatched; - + } @@ -2558,7 +2779,7 @@ sub SIGNALduino_Ready($) { $hash->{DevState} = 'disconnected'; return DevIo_OpenDev($hash, 1, "SIGNALduino_DoInit", 'SIGNALduino_Connect') } - + # This is relevant for windows/USB only my $po = $hash->{USBDev}; my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags); @@ -2571,9 +2792,9 @@ sub SIGNALduino_Ready($) { ############################### sub SIGNALduino_WriteInit($) { my ($hash) = @_; - + # todo: ist dies so ausreichend, damit die Aenderungen uebernommen werden? - SIGNALduino_AddSendQueue($hash,"WS36"); # SIDLE, Exit RX / TX, turn off frequency synthesizer + SIGNALduino_AddSendQueue($hash,"WS36"); # SIDLE, Exit RX / TX, turn off frequency synthesizer SIGNALduino_AddSendQueue($hash,"WS34"); # SRX, Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1. } @@ -2583,7 +2804,7 @@ sub SIGNALduino_SimpleWrite(@) { return if(!$hash); if($hash->{TYPE} eq "SIGNALduino_RFR") { # Prefix $msg with RRBBU and return the corresponding SIGNALduino hash. - ($hash, $msg) = SIGNALduino_RFR_AddPrefix($hash, $msg); + ($hash, $msg) = SIGNALduino_RFR_AddPrefix($hash, $msg); } my $name = $hash->{NAME}; @@ -2604,10 +2825,10 @@ sub SIGNALduino_Attr(@) { my ($cmd,$name,$aName,$aVal) = @_; my $hash = $defs{$name}; my $debug = AttrVal($name,"debug",0); - + $aVal= "" if (!defined($aVal)); $hash->{logMethod}->($name, 4, "$name: Attr, Calling sub with args: $cmd $aName = $aVal"); - + if( $aName eq "Clients" ) { ## Change clientList $hash->{Clients} = $aVal; $hash->{Clients} = $clientsSIGNALduino if( !$hash->{Clients}) ; ## Set defaults @@ -2620,7 +2841,7 @@ sub SIGNALduino_Attr(@) { $hash->{logMethod}->($name, 2, $name .": Attr, $aVal: ". $@); } } - + if( ref($match_list) eq 'HASH' ) { $hash->{MatchList} = $match_list; } else { @@ -2632,7 +2853,7 @@ sub SIGNALduino_Attr(@) { { $hash->{logMethod}->($name, 3, "$name: Attr, setting Verbose to: " . $aVal); $hash->{unknownmessages}="" if $aVal <4; - + } elsif ($aName eq "debug") { @@ -2678,17 +2899,18 @@ sub SIGNALduino_Attr(@) { } } } - elsif ($aName eq "cc1101_frequency") - { - if ($aVal eq "" || $aVal < 800) { - $hash->{logMethod}->($name, 3, "$name: Attr, delete cc1101_frequency"); - delete ($hash->{cc1101_frequency}) if (defined($hash->{cc1101_frequency})); - } else { - $hash->{logMethod}->($name, 3, "$name: Attr, setting cc1101_frequency to 868"); - $hash->{cc1101_frequency} = 868; - } - } - + ####### Beginn kann wahrscheinlich weg ####### + # elsif ($aName eq "cc1101_frequency") + # { + # if ($aVal eq "" || $aVal < 800) { + # $hash->{logMethod}->($name, 3, "$name: Attr, delete cc1101_frequency"); + # delete ($hash->{cc1101_frequency}) if (defined($hash->{cc1101_frequency})); + # } else { + # $hash->{logMethod}->($name, 3, "$name: Attr, setting cc1101_frequency to 868"); + # $hash->{cc1101_frequency} = 868; + # } + # } + ####### Ende kann wahrscheinlich weg ####### elsif ($aName eq "hardware") # to set flashCommand if hardware def or change { # to delete flashCommand if hardware delete @@ -2699,36 +2921,36 @@ sub SIGNALduino_Attr(@) { elsif ($aName eq "eventlogging") # enable / disable eventlogging { if ($aVal == 1) { - $hash->{logMethod} = \&::SIGNALduino_Log3; + $hash->{logMethod} = \&::SIGNALduino_Log3; Log3 $name, 3, "$name: Attr, Enable eventlogging"; } else { - $hash->{logMethod} = \&::Log3; + $hash->{logMethod} = \&::Log3; Log3 $name, 3, "$name: Attr, Disable eventlogging"; } } - + return undef; } ############################### sub SIGNALduino_FW_Detail($@) { my ($FW_wname, $name, $room, $pageHash) = @_; - + my $hash = $defs{$name}; - + my @dspec=devspec2array("DEF=.*fakelog"); my $lfn = $dspec[0]; my $fn=$defs{$name}->{TYPE}."-Flash.log"; - + my $ret = "
Information menu "; if (-s AttrVal("global", "logdir", "./log/") .$fn) - { + { my $flashlogurl="$FW_ME/FileLog_logWrapper?dev=$lfn&type=text&file=$fn"; - + $ret .= ""; @@ -2736,15 +2958,15 @@ sub SIGNALduino_FW_Detail($@) { } my $protocolURL="$FW_ME/FileLog_logWrapper?dev=$lfn&type=text&file=$fn"; - + $ret.=""; $ret .= '
"; $ret .= "Last Flashlog<\/a>"; $ret .= "Display protocollist
- +