diff --git a/FHEM/00_CUL.pm b/FHEM/00_CUL.pm new file mode 100644 index 0000000..a42fcb4 --- /dev/null +++ b/FHEM/00_CUL.pm @@ -0,0 +1,1738 @@ +############################################## +# $Id: 00_CUL.pm 14119 2017-04-27 11:41:18Z rudolfkoenig $ +package main; + +use strict; +use warnings; +use Time::HiRes qw(gettimeofday); + +sub CUL_Attr(@); +sub CUL_Clear($); +sub CUL_HandleCurRequest($$); +sub CUL_HandleWriteQueue($); +sub CUL_Parse($$$$@); +sub CUL_Read($); +sub CUL_ReadAnswer($$$$); +sub CUL_Ready($); +sub CUL_Write($$$); + +sub CUL_SimpleWrite(@); +sub CUL_WriteInit($); + +my %gets = ( # Name, Data to send to the CUL, Regexp for the answer + "ccconf" => 1, + "version" => ["V", '^V .*'], + "raw" => ["", '.*'], + "uptime" => ["t", '^[0-9A-F]{8}[\r\n]*$' ], + "fhtbuf" => ["T03", '^[0-9A-F]+[\r\n]*$' ], + "cmds" => ["?", '.*Use one of( .)*[\r\n]*$' ], + "credit10ms" => [ "X", '^.. *\d*[\r\n]*$' ], +); + +my %sets = ( + "reopen" => "", + "hmPairForSec" => "HomeMatic", + "hmPairSerial" => "HomeMatic", + "raw" => "", + "freq" => "SlowRF", + "bWidth" => "SlowRF", + "rAmpl" => "SlowRF", + "sens" => "SlowRF", + "led" => "", + "patable" => "", + "ITClock" => "SlowRF" +); + +my @ampllist = (24, 27, 30, 33, 36, 38, 40, 42); # rAmpl(dB) + +my $sccMods = "STACKABLE_CC:TSSTACKED:STACKABLE"; +my $culNameRe = "^(CUL|TSCUL)\$"; + +my $clientsSlowRF = ":FS20:FHT.*:KS300:USF1000:BS:HMS: ". + ":CUL_EM:CUL_WS:CUL_FHTTK:CUL_HOERMANN: ". + ":ESA2000:CUL_IR:CUL_TX:Revolt:IT:UNIRoll:SOMFY: ". + ":$sccMods:CUL_RFR::CUL_TCM97001:CUL_REDIRECT:"; +my $clientsHomeMatic = ":CUL_HM:HMS:CUL_IR:$sccMods:"; +my $clientsMAX = ":CUL_MAX:HMS:CUL_IR:$sccMods:"; +my $clientsWMBus = ":WMBUS:HMS:CUL_IR:$sccMods:"; +my $clientsKOPP_FC = ":KOPP_FC:HMS:CUL_IR:$sccMods:"; +my $clientsBetty = ":Betty:HMS:CUL_IR:$sccMods:"; + +my %matchListSlowRF = ( + "1:USF1000" => "^81..(04|0c)..0101a001a5ceaa00....", + "2:BS" => "^81..(04|0c)..0101a001a5cf", + "3:FS20" => "^81..(04|0c)..0101a001", + "4:FHT" => "^81..(04|09|0d)..(0909a001|83098301|c409c401)..", + "5:KS300" => "^810d04..4027a001", + "6:CUL_WS" => "^K.....", + "7:CUL_EM" => "^E0.................\$", + "8:HMS" => "^810e04....(1|5|9).a001", + "9:CUL_FHTTK" => "^T[A-F0-9]{8}", + "A:CUL_RFR" => "^[0-9A-F]{4}U.", + "B:CUL_HOERMANN"=> "^R..........", + "C:ESA2000" => "^S................................\$", + "D:CUL_IR" => "^I............", + "E:CUL_TX" => "^TX[A-F0-9]{10}", + "F:Revolt" => "^r......................\$", + "G:IT" => "^i......", + "H:STACKABLE_CC"=>"^\\*", + "I:UNIRoll" => "^[0-9A-F]{5}(B|D|E)", + "J:SOMFY" => "^Y[r|t|s]:?[A-F0-9]+", + "K:CUL_TCM97001" => "^s[A-F0-9]+", + "L:CUL_REDIRECT" => "^o+", + "M:TSSTACKED"=>"^\\*", + "N:STACKABLE"=>"^\\*", +); + +my %matchListHomeMatic = ( + "1:CUL_HM" => "^A....................", + "8:HMS" => "^810e04....(1|5|9).a001", # CUNO OneWire HMS Emulation + "D:CUL_IR" => "^I............", + "H:STACKABLE_CC"=>"^\\*", + "M:TSSTACKED"=>"^\\*", + "N:STACKABLE"=>"^\\*", +); + +my %matchListMAX = ( + "1:CUL_MAX" => "^Z........................", + "8:HMS" => "^810e04....(1|5|9).a001", # CUNO OneWire HMS Emulation + "D:CUL_IR" => "^I............", + "H:STACKABLE_CC"=>"^\\*", + "M:TSSTACKED"=>"^\\*", + "N:STACKABLE"=>"^\\*", +); + +my %matchListWMBus = ( + "J:WMBUS" => "^b.*", + "8:HMS" => "^810e04....(1|5|9).a001", # CUNO OneWire HMS Emulation + "D:CUL_IR" => "^I............", + "H:STACKABLE_CC"=>"^\\*", + "M:TSSTACKED"=>"^\\*", + "N:STACKABLE"=>"^\\*", +); + +my %matchListKOPP_FC = ( + "1:Kopp_FC" => "^kr..................", + "8:HMS" => "^810e04....(1|5|9).a001", # CUNO OneWire HMS Emulation + "D:CUL_IR" => "^I............", + "H:STACKABLE_CC"=>"^\\*", + "M:TSSTACKED"=>"^\\*", + "N:STACKABLE"=>"^\\*", +); + +my %matchListBetty = ( + "8:HMS" => "^810e04....(1|5|9).a001", # CUNO OneWire HMS Emulation + "D:CUL_IR" => "^I............", + "H:STACKABLE_CC"=>"^\\*", + "M:TSSTACKED"=>"^\\*", + "N:STACKABLE"=>"^\\*", + "O:Betty" => "^y.*", +); + +sub +CUL_Initialize($) +{ + my ($hash) = @_; + + require "$attr{global}{modpath}/FHEM/DevIo.pm"; + +# Provider + $hash->{ReadFn} = "CUL_Read"; + $hash->{WriteFn} = "CUL_Write"; + $hash->{ReadyFn} = "CUL_Ready"; + +# Normal devices + $hash->{DefFn} = "CUL_Define"; + $hash->{FingerprintFn} = "CUL_FingerprintFn"; + $hash->{UndefFn} = "CUL_Undef"; + $hash->{GetFn} = "CUL_Get"; + $hash->{SetFn} = "CUL_Set"; + $hash->{AttrFn} = "CUL_Attr"; + no warnings 'qw'; + my @attrList = qw( + addvaltrigger + connectCommand + do_not_notify:1,0 + dummy:1,0 + hmId longids + hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger + model:CUL,CUN,CUNO,SCC,nanoCUL + rfmode:SlowRF,HomeMatic,MAX,WMBus_T,WMBus_S,KOPP_FC,Betty + sendpool + showtime:1,0 + ); + use warnings 'qw'; + $hash->{AttrList} = join(" ", @attrList)." ".$readingFnAttributes; + $hash->{ShutdownFn} = "CUL_Shutdown"; +} + +sub +CUL_FingerprintFn($$) +{ + my ($name, $msg) = @_; + + # Store only the "relevant" part, as the CUL won't compute the checksum + $msg = substr($msg, 8) if($msg =~ m/^81/ && length($msg) > 8); + + return ($name, $msg); +} + +##################################### +sub +CUL_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + + if(@a < 4 || @a > 5) { + my $msg = "wrong syntax: define CUL {none | devicename[\@baudrate] ". + "| devicename\@directio | hostname:port} "; + Log3 undef, 2, $msg; + return $msg; + } + + DevIo_CloseDev($hash); + + my $name = $a[0]; + my $dev = $a[2]; + return "FHTID must be H1H2, with H1 and H2 hex and both smaller than 64" + if(uc($a[3]) !~ m/^[0-6][0-9A-F][0-6][0-9A-F]$/); + + if(uc($a[3]) =~ m/^([0-6][0-9A-F])/ && $1 ne "00") { + my $x = $1; + foreach my $d (keys %defs) { + next if($d eq $name); + if($defs{$d}{TYPE} =~ m/$culNameRe/) { + if(uc($defs{$d}{FHTID}) =~ m/^$x/) { + my $m = "$name: Cannot define multiple CULs with identical ". + "first two digits ($x)"; + Log3 $name, 1, $m; + return $m; + } + } + } + } + $hash->{FHTID} = uc($a[3]); + $hash->{initString} = "X21"; + $hash->{CMDS} = ""; + $hash->{Clients} = $clientsSlowRF; + $hash->{MatchList} = \%matchListSlowRF; + + if($dev eq "none") { + Log3 $name, 1, "$name device is none, commands will be echoed only"; + $attr{$name}{dummy} = 1; + return undef; + } + + $hash->{DeviceName} = $dev; + my $ret = DevIo_OpenDev($hash, 0, "CUL_DoInit"); + return $ret; +} + +##################################### +sub +CUL_Undef($$) +{ + my ($hash, $arg) = @_; + my $name = $hash->{NAME}; + + foreach my $d (sort keys %defs) { + if(defined($defs{$d}) && + defined($defs{$d}{IODev}) && + $defs{$d}{IODev} == $hash) + { + my $lev = ($reread_active ? 4 : 2); + Log3 $name, $lev, "deleting port for $d"; + delete $defs{$d}{IODev}; + } + } + + CUL_SimpleWrite($hash, "X00"); # Switch reception off, it may hang up the CUL + DevIo_CloseDev($hash); + return undef; +} + +##################################### +sub +CUL_Shutdown($) +{ + my ($hash) = @_; + CUL_SimpleWrite($hash, "X00"); + return undef; +} + +sub +CUL_RemoveHMPair($) +{ + my $hash = shift; + delete($hash->{hmPair}); +} + +##################################### +sub +CUL_Reopen($) +{ + my ($hash) = @_; + DevIo_CloseDev($hash); + DevIo_OpenDev($hash, 1, "CUL_DoInit"); +} + +##################################### +sub +CUL_Set($@) +{ + my ($hash, @a) = @_; + + return "\"set CUL\" needs at least one parameter" if(@a < 2); + return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets) + if(!defined($sets{$a[1]})); + + my $name = shift @a; + my $type = shift @a; + my $arg = join("", @a); + + return "This command is not valid in the current rfmode" + if($sets{$type} && $sets{$type} ne AttrVal($name, "rfmode", "SlowRF")); + + if($type eq "reopen") { + CUL_Reopen($hash); + + } elsif($type eq "hmPairForSec") { + return "Usage: set $name hmPairForSec " + if(!$arg || $arg !~ m/^\d+$/); + $hash->{hmPair} = 1; + InternalTimer(gettimeofday()+$arg, "CUL_RemoveHMPair", $hash, 1); + + } elsif($type eq "hmPairSerial") { + return "Usage: set $name hmPairSerial <10-character-serialnumber>" + if(!$arg || $arg !~ m/^.{10}$/); + + my $id = AttrVal($hash->{NAME}, "hmId", "F1".$hash->{FHTID}); + $hash->{HM_CMDNR} = $hash->{HM_CMDNR} ? ($hash->{HM_CMDNR}+1)%256 : 1; + CUL_SimpleWrite($hash, sprintf("As15%02x8401%s000000010A%s", + $hash->{HM_CMDNR}, $id, unpack('H*', $arg))); + $hash->{hmPairSerial} = $arg; + + } elsif($type eq "freq") { + + 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); + Log3 $name, 3, "Setting FREQ2..0 (0D,0E,0F) to $f2 $f1 $f0 = $arg MHz"; + CUL_SimpleWrite($hash, "W0F$f2"); + CUL_SimpleWrite($hash, "W10$f1"); + CUL_SimpleWrite($hash, "W11$f0"); + CUL_WriteInit($hash); # Will reprogram the CC1101 + + } elsif($type eq "bWidth") { + my ($err, $ob); + if(!IsDummy($hash->{NAME})) { + CUL_SimpleWrite($hash, "C10"); + ($err, $ob) = CUL_ReadAnswer($hash, $type, 0, "^C10 = .*"); + return "Can't get old MDMCFG4 value" if($err || $ob !~ m,/ (.*)\r,); + $ob = $1 & 0x0f; + } + + my ($bits, $bw) = (0,0); + 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 + goto GOTBW if($arg >= $bw); + } + } + +GOTBW: + $ob = sprintf("%02x", $ob+$bits); + Log3 $name, 3, "Setting MDMCFG4 (10) to $ob = $bw KHz"; + CUL_SimpleWrite($hash, "W12$ob"); + CUL_WriteInit($hash); + + } elsif($type 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]; + Log3 $name, 3, "Setting AGCCTRL2 (1B) to $v / $w dB"; + CUL_SimpleWrite($hash, "W1D$v"); + CUL_WriteInit($hash); + + } elsif($type 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); + Log3 $name, 3, "Setting AGCCTRL0 (1D) to $v / $w dB"; + CUL_SimpleWrite($hash, "W1F$v"); + CUL_WriteInit($hash); + + } elsif( $type eq "ITClock" ) { + my $clock = shift @a; + $clock=250 if($clock eq ""); + return "argument $arg is not numeric" if($clock !~ /^\d+$/); + Log3 $name, 3, "set $name $type $clock"; + $arg="ic$clock"; + CUL_SimpleWrite($hash, $arg); + + } else { + return "Expecting a 0-padded hex number" + if((length($arg)&1) == 1 && $type ne "raw"); + Log3 $name, 3, "set $name $type $arg"; + $arg = "l$arg" if($type eq "led"); + $arg = "x$arg" if($type eq "patable"); + CUL_SimpleWrite($hash, $arg); + + } + return undef; +} + +##################################### +sub +CUL_Get($@) +{ + my ($hash, @a) = @_; + my $type = $hash->{TYPE}; + + return "\"get $type\" needs at least one parameter" if(@a < 2); + if(!defined($gets{$a[1]})) { + my @cList = map { $_ =~ m/^(file|raw)$/ ? $_ : "$_:noArg" } sort keys %gets; + return "Unknown argument $a[1], choose one of " . join(" ", @cList); + } + + my $arg = ($a[2] ? $a[2] : ""); + my ($msg, $err); + my $name = $a[0]; + + return "No $a[1] for dummies" if(IsDummy($name)); + + if($a[1] eq "ccconf") { + + my %r = ( "0D"=>1,"0E"=>1,"0F"=>1,"10"=>1,"1B"=>1,"1D"=>1 ); + foreach my $a (sort keys %r) { + CUL_SimpleWrite($hash, "C$a"); + ($err, $msg) = CUL_ReadAnswer($hash, "C$a", 0, "^C.* = .*"); + return $err if($err); + my @answ = split(" ", $msg); + $r{$a} = $answ[4]; + } + $msg = sprintf("freq:%.3fMHz bWidth:%dKHz rAmpl:%ddB sens:%ddB", + 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], + 4+4*($r{"1D"}&3) #Sens + ); + + } else { + + CUL_SimpleWrite($hash, $gets{$a[1]}[0] . $arg); + my $mtch = defined($a[3]) ? $a[3] : $gets{$a[1]}[1]; # optional + ($err, $msg) = CUL_ReadAnswer($hash, $a[1], 0, $mtch); + if(!defined($msg)) { + DevIo_Disconnected($hash); + $msg = "No answer"; + + } elsif($a[1] eq "cmds") { # nice it up + $msg =~ s/.*Use one of//g; + + } elsif($a[1] eq "uptime") { # decode it + $msg =~ s/[\r\n]//g; + $msg = hex($msg)/125; + $msg = sprintf("%d %02d:%02d:%02d", + $msg/86400, ($msg%86400)/3600, ($msg%3600)/60, $msg%60); + } elsif($a[1] eq "credit10ms") { + ($msg) = ($msg =~ /^.. *(\d*)[\r\n]*$/); + } + + $msg =~ s/[\r\n]//g; + + } + + readingsSingleUpdate($hash, $a[1], $msg, 1); + + return "$a[0] $a[1] => $msg"; +} + +sub +CUL_Clear($) +{ + my $hash = shift; + + # Clear the pipe + $hash->{RA_Timeout} = 0.1; + for(;;) { + my ($err, undef) = CUL_ReadAnswer($hash, "Clear", 0, "wontmatch"); + last if($err); + } + delete($hash->{RA_Timeout}); + $hash->{PARTIAL} = ""; +} + +##################################### +sub +CUL_DoInit($) +{ + my $hash = shift; + my $name = $hash->{NAME}; + my $err; + my $msg = undef; + + CUL_Clear($hash); + my ($ver, $try) = ("", 0); + while($try++ < 3 && $ver !~ m/^V/) { + CUL_SimpleWrite($hash, "V"); + ($err, $ver) = CUL_ReadAnswer($hash, "Version", 0, "^V"); + return "$name: $err" if($err && ($err !~ m/Timeout/ || $try == 3)); + $ver = "" if(!$ver); + } + + if($ver !~ m/^V/) { + $attr{$name}{dummy} = 1; + $msg = "Not an CUL device, got for V: $ver"; + Log3 $name, 1, $msg; + return $msg; + } + $ver =~ s/[\r\n]//g; + $hash->{VERSION} = $ver; + + # Cmd-String feststellen + + my $cmds = CUL_Get($hash, $name, "cmds", 0); + $cmds =~ s/$name cmds =>//g; + $cmds =~ s/ //g; + $hash->{CMDS} = $cmds; + Log3 $name, 3, "$name: Possible commands: " . $hash->{CMDS}; + + CUL_WriteInit($hash); + + # FHTID + if(defined($hash->{FHTID})) { + my $fhtid; + CUL_SimpleWrite($hash, "T01"); + ($err, $fhtid) = CUL_ReadAnswer($hash, "FHTID", 0, undef); + return "$name: $err" if($err); + $fhtid =~ s/[\r\n]//g; + Log3 $name, 5, "GOT CUL fhtid: $fhtid"; + if(!defined($fhtid) || $fhtid ne $hash->{FHTID}) { + Log3 $name, 2, "Setting $name fhtid from $fhtid to " . $hash->{FHTID}; + CUL_SimpleWrite($hash, "T01" . $hash->{FHTID}); + } + } + + my $cc = AttrVal($name, "connectCommand", undef); + CUL_SimpleWrite($hash, $cc) if($cc); + + readingsSingleUpdate($hash, "state", "Initialized", 1); + + # Reset the counter + delete($hash->{XMIT_TIME}); + delete($hash->{NR_CMD_LAST_H}); + return undef; +} + +##################################### +# This is a direct read for commands like get +# Anydata is used by read file to get the filesize +sub +CUL_ReadAnswer($$$$) +{ + my ($hash, $arg, $anydata, $regexp) = @_; + my $ohash = $hash; + + while($hash && $hash->{TYPE} !~ m/$culNameRe/) { + $hash = $hash->{IODev}; + } + return ("No FD", undef) + if(!$hash || ($^O !~ /Win/ && !defined($hash->{FD}))); + + my ($mculdata, $rin) = ("", ''); + my $buf; + my $to = 3; # 3 seconds timeout + $mculdata = $hash->{PARTIAL} if(defined($hash->{PARTIAL})); + + $to = $ohash->{RA_Timeout} if($ohash->{RA_Timeout}); # ...or less + for(;;) { + + if($^O =~ m/Win/ && $hash->{USBDev}) { + $hash->{USBDev}->read_const_time($to*1000); # set timeout (ms) + # Read anstatt input sonst funzt read_const_time nicht. + $buf = $hash->{USBDev}->read(999); + return ("Timeout reading answer for get $arg", undef) + if(length($buf) == 0); + + } else { + return ("Device lost when reading answer for get $arg", undef) + if(!$hash->{FD}); + + vec($rin, $hash->{FD}, 1) = 1; + my $nfound = select($rin, undef, undef, $to); + if($nfound < 0) { + next if ($! == EAGAIN() || $! == EINTR() || $! == 0); + my $err = $!; + DevIo_Disconnected($hash); + return("CUL_ReadAnswer $arg: $err", undef); + } + return ("Timeout reading answer for get $arg", undef) + if($nfound == 0); + $buf = DevIo_SimpleRead($hash); + return ("No data", undef) if(!defined($buf)); + + } + + if(defined($buf)) { + Log3 $ohash->{NAME}, 5, "CUL/RAW (ReadAnswer): $buf"; + $mculdata .= $buf; + } + + # Dispatch data in the buffer before the proper answer. + while(($mculdata =~ m/^([^\n]*\n)(.*)/s) || $anydata) { + my $line = ($anydata ? $mculdata : $1); + $mculdata = $2; + $hash->{PARTIAL} = $mculdata; # for recursive calls + (undef, $line) = CUL_prefix(0, $ohash, $line); # Delete prefix + if($regexp && $line !~ m/$regexp/) { + $line =~ s/[\n\r]+//g; + CUL_Parse($ohash, $hash, $ohash->{NAME}, $line) if($init_done); + $mculdata = $hash->{PARTIAL}; + } else { + return (undef, $line); + } + } + } +} + +##################################### +# Check if the 1% limit is reached and trigger notifies +sub +CUL_XmitLimitCheck($$$) +{ + my ($hash,$fn,$now) = @_; + + if(!$hash->{XMIT_TIME}) { + $hash->{XMIT_TIME}[0] = $now; + $hash->{NR_CMD_LAST_H} = 1; + return; + } + + my $nowM1h = $now-3600; + my @b = grep { $_ > $nowM1h } @{$hash->{XMIT_TIME}}; + + # Maximum nr of transmissions per hour, but not for HM and MAX + if(@b > 163 && $fn !~ m/^[AZ]/) { + my $name = $hash->{NAME}; + Log3 $name, 2, "CUL TRANSMIT LIMIT EXCEEDED"; + DoTrigger($name, "TRANSMIT LIMIT EXCEEDED"); + + } else { + + push(@b, $now); + + } + $hash->{XMIT_TIME} = \@b; + $hash->{NR_CMD_LAST_H} = int(@b); +} + +sub +CUL_XmitDlyHM($$$) +{ + my ($hash,$fn,$now) = @_; + + my (undef,$mTy,undef,$id) = unpack 'A8A2A6A6',$fn if(length($fn)>19); + + if($id && + $modules{CUL_HM}{defptr}{$id} && + $modules{CUL_HM}{defptr}{$id}{helper}{io} && + $modules{CUL_HM}{defptr}{$id}{helper}{io}{nextSend}) { + my $dDly = $modules{CUL_HM}{defptr}{$id}{helper}{io}{nextSend} - $now; + #$dDly -= 0.04 if ($mTy eq "02");# while HM devices need a rest there are + # still some devices that need faster + # reactionfor ack. + # Mode needs to be determined + if ($dDly > 0.01){# wait less then 10 ms will not work + $dDly = 0.1 if($dDly > 0.1); + Log3 $hash->{NAME}, 5, "CUL $id dly:".int($dDly*1000)."ms"; + select(undef, undef, undef, $dDly); + } + } + shift(@{$hash->{helper}{$id}{QUEUE}}); + InternalTimer($now+0.1, "CUL_XmitDlyHMTo", "$hash->{NAME}:$id", 1) + if (scalar(@{$hash->{helper}{$id}{QUEUE}})); + return 0; +} + +sub +CUL_XmitDlyHMTo($) +{ # waited long enough - next send for this ID + my ($name,$id) = split(":",$_[0]); + CUL_SendFromQueue($defs{$name}, ${$defs{$name}{helper}{$id}{QUEUE}}[0]); +} + +##################################### +# Translate data prepared for an FHZ to CUL syntax, so we can reuse +# the FS20 and FHZ modules. +sub +CUL_WriteTranslate($$$) +{ + my ($hash,$fn,$msg) = @_; + + ################### + # Rewrite message from FHZ -> CUL + if(length($fn) <= 1) { # CUL Native + ; + + } elsif($fn eq "04" && substr($msg,0,6) eq "010101") { # FS20 + $fn = "F"; + AddDuplicate($hash->{NAME}, + "0101a001" . substr($msg, 6, 6) . "00" . substr($msg, 12)); + $msg = substr($msg,6); + + } elsif($fn eq "04" && substr($msg,0,6) eq "020183") { # FHT + $fn = "T"; + $msg = substr($msg,6,4) . substr($msg,10); + + } elsif($fn eq "cmd") { # internal command + if($msg eq "speed100") { + $fn = "AR"; + } elsif($msg eq "speed10") { + $fn = "Ar"; + } else { # by default rewrite init + $fn = $hash->{initString}; + } + $msg = ""; + + } else { + Log3 $hash, 2, "CUL cannot translate $fn $msg"; + return (undef, undef); + } + return ($fn, $msg); +} + +##################################### +sub +CUL_Write($$$) +{ + my ($hash,$fn,$msg) = @_; + + ($fn, $msg) = CUL_WriteTranslate($hash, $fn, $msg); + return if(!defined($fn)); + my $name = $hash->{NAME}; + Log3 $name, 5, "$hash->{NAME} sending $fn$msg"; + my $bstring = "$fn$msg"; + + if($fn eq "F" || # FS20 message + $bstring =~ m/^u....F/ || # FS20 messages sent over an RFR + ($fn eq "" && ($bstring =~ m/^A/ || $bstring =~ m/^Z/ ))) { # AskSin/BidCos/HomeMatic/MAX + + CUL_AddSendQueue($hash, $bstring); + + } else { + + CUL_SimpleWrite($hash, $bstring); + + } + +} + +sub +CUL_SendFromQueue($$) +{ + my ($hash, $bstring) = @_; + my $name = $hash->{NAME}; + my $hm = ($bstring =~ m/^A/); + my $to = ($hm ? 0.15 : 0.3); + my $now = gettimeofday(); + if($bstring ne "") { + my $sp = AttrVal($name, "sendpool", undef); + if($sp) { # Is one of the CUL-fellows sending data? + my @fellows = split(",", $sp); + foreach my $f (@fellows) { + if($f ne $name && + $defs{$f} && + $defs{$f}{QUEUE} && + $defs{$f}{QUEUE}->[0] ne ""){ + unshift(@{$hash->{QUEUE}}, ""); + InternalTimer($now+$to, "CUL_HandleWriteQueue", $hash, 1); + return; + } + } + } + + CUL_XmitLimitCheck($hash, $bstring, $now); + if($hm) { + CUL_SimpleWrite($hash, $bstring) if(!CUL_XmitDlyHM($hash,$bstring,$now)); + return; + } else { + CUL_SimpleWrite($hash, $bstring); + } + } + + ############## + # Write the next buffer not earlier than 0.23 seconds + # = 3* (12*0.8+1.2+1.0*5*9+0.8+10) = 226.8ms + # else it will be sent too early by the CUL, resulting in a collision + InternalTimer($now+$to, "CUL_HandleWriteQueue", $hash, 1); +} + +sub +CUL_AddSendQueue($$) +{ + my ($hash, $bstring) = @_; + my $qHash = $hash; + if ($bstring =~ m/^A/){ # HM device + my $id = substr($bstring,16,6);#get HMID destination + $qHash = $hash->{helper}{$id}; + } + if(!$qHash->{QUEUE} || 0 == scalar(@{$qHash->{QUEUE}})) { + $qHash->{QUEUE} = [ $bstring ]; + CUL_SendFromQueue($hash, $bstring); + } else { + push(@{$qHash->{QUEUE}}, $bstring); + } +} + +##################################### +sub +CUL_HandleWriteQueue($) +{ + my $hash = shift; + my $arr = $hash->{QUEUE}; + if(defined($arr) && @{$arr} > 0) { + shift(@{$arr}); + if(@{$arr} == 0) { + delete($hash->{QUEUE}); + return; + } + my $bstring = $arr->[0]; + if($bstring eq "") { + CUL_HandleWriteQueue($hash); + } else { + CUL_SendFromQueue($hash, $bstring); + } + } +} + +##################################### +# called from the global loop, when the select for hash->{FD} reports data +sub +CUL_Read($) +{ + my ($hash) = @_; + + my $buf = DevIo_SimpleRead($hash); + return "" if(!defined($buf)); + my $name = $hash->{NAME}; + + my $culdata = $hash->{PARTIAL}; + Log3 $name, 5, "CUL/RAW: $culdata/$buf"; + $culdata .= $buf; + + while($culdata =~ m/\n/) { + my $rmsg; + ($rmsg,$culdata) = split("\n", $culdata, 2); + $rmsg =~ s/\r//; + $hash->{PARTIAL} = $culdata; # for recursive calls + CUL_Parse($hash, $hash, $name, $rmsg) if($rmsg); + $culdata = $hash->{PARTIAL}; + } + $hash->{PARTIAL} = $culdata; +} + +sub +CUL_Parse($$$$@) +{ + my ($hash, $iohash, $name, $rmsg, $initstr) = @_; + + if($rmsg =~ m/^V/) { # CUN* keepalive + Log3 $name, 4, "CUL_Parse: $name $rmsg"; + return; + } + + my $rssi; + my $dmsg = $rmsg; + my $dmsgLog = (AttrVal($name,"rfmode","") eq "HomeMatic") + ? join(" ",(unpack'A1A2A2A4A6A6A*',$rmsg)) + :$dmsg; + if($dmsg =~ m/^[AFTKEHRStZriby]([A-F0-9][A-F0-9])+$/) { # RSSI + my $l = length($dmsg); + $rssi = hex(substr($dmsg, $l-2, 2)); + $dmsg = substr($dmsg, 0, $l-2); + $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); + Log3 $name, 4, "CUL_Parse: $name $dmsgLog $rssi"; + } else { + Log3 $name, 4, "CUL_Parse: $name $dmsgLog"; + } + + ########################################### + #Translate Message from CUL to FHZ + next if(!$dmsg || length($dmsg) < 1); # Bogus messages + + if ($dmsg eq 'SMODE' || $dmsg eq 'TMODE') { # brs/brt returns SMODE/TMODE + Log3 $name, 5, "CUL_Parse: switched to $dmsg"; + return; + } + + if($dmsg =~ m/^[0-9A-F]{4}U./) { # RF_ROUTER + Dispatch($hash, $dmsg, undef); + return; + } + + my $fn = substr($dmsg,0,1); + my $len = length($dmsg); + + if($fn eq "F" && $len >= 9) { # Reformat for 10_FS20.pm + CUL_AddSendQueue($iohash, ""); # Delay immediate replies + $dmsg = sprintf("81%02x04xx0101a001%s00%s", + $len/2+7, substr($dmsg,1,6), substr($dmsg,7)); + $dmsg = lc($dmsg); + + } elsif($fn eq "T") { + if ($len >= 11) { # Reformat for 11_FHT.pm + $dmsg = sprintf("81%02x04xx0909a001%s00%s", + $len/2+7, substr($dmsg,1,6), substr($dmsg,7)); + $dmsg = lc($dmsg); + } + + } elsif($fn eq "H" && $len >= 13) { # Reformat for 12_HMS.pm + my $type = hex(substr($dmsg,6,1)); + my $stat = $type > 1 ? hex(substr($dmsg,7,2)) : hex(substr($dmsg,5,2)); + my $prf = $type > 1 ? "02" : "05"; + my $bat = $type > 1 ? hex(substr($dmsg,5,1))+1 : 1; + my $HA = substr($dmsg,1,4); + my $values = $type > 1 ? "000000" : substr($dmsg,7); + $dmsg = sprintf("81%02x04xx%s%x%xa001%s0000%02x%s", + $len/2+8, # Packet-Length + $prf, $bat, $type, + $HA, # House-Code + $stat, + $values); # Values + $dmsg = lc($dmsg); + + } elsif($fn eq "K" && $len >= 5) { + if($len == 15) { # Reformat for 13_KS300.pm + my @a = split("", $dmsg); + $dmsg = sprintf("81%02x04xx4027a001", $len/2+6); + for(my $i = 1; $i < 14; $i+=2) { # Swap nibbles. + $dmsg .= $a[$i+1] . $a[$i]; + } + $dmsg = lc($dmsg); + } + # Other K... Messages ar sent to CUL_WS + } elsif($fn eq "r" && $len >= 23) { # Revolt + $dmsg = lc($dmsg); + } elsif($fn eq "i" && $len >= 7) { # IT + $dmsg = lc($dmsg); + } elsif($fn eq "A" && $len >= 20) { # AskSin/BidCos/HomeMatic + my $src = substr($dmsg,9,6); + if($modules{CUL_HM}{defptr}{$src}){ + $modules{CUL_HM}{defptr}{$src}{helper}{io}{nextSend} = + gettimeofday() + 0.100; + } + $dmsg .= "::$rssi:$name" if(defined($rssi)); + + } elsif($fn eq "Z" && $len >= 21) { # Moritz/Max + ; + } elsif($fn eq "b" && $len >= 24) { # Wireless M-Bus + $dmsg .= "::$rssi" if (defined($rssi)); + } elsif($fn eq "t" && $len >= 5) { # TX3 + $dmsg = "TX".substr($dmsg,1); # t.* is occupied by FHTTK + } + + $hash->{"${name}_MSGCNT"}++; + $hash->{"${name}_TIME"} = TimeNow(); + # showtime attribute + readingsSingleUpdate($hash, "state", $hash->{READINGS}{state}{VAL}, 0); + $hash->{RAWMSG} = $rmsg; + my %addvals = (RAWMSG => $dmsg); + if(defined($rssi)) { + $hash->{RSSI} = $rssi; + $addvals{RSSI} = $rssi; + } + Dispatch($hash, $dmsg, \%addvals); +} + + +##################################### +sub +CUL_Ready($) +{ + my ($hash) = @_; + + return DevIo_OpenDev($hash, 1, "CUL_DoInit") + if($hash->{STATE} eq "disconnected"); + + # This is relevant for windows/USB only + my $po = $hash->{USBDev}; + my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags); + if($po) { + ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status; + } + return ($InBytes && $InBytes>0); +} + +######################## +# Needed for STACKABLE_CC +sub +CUL_WriteInit($) +{ + my ($hash) = @_; + foreach my $is (split("\n", $hash->{initString})) { + CUL_SimpleWrite($hash, $is); + } +} + +sub +CUL_SimpleWrite(@) +{ + my ($hash, $msg, $nonl) = @_; + return if(!$hash); + ($hash, $msg) = CUL_prefix(1, $hash, $msg); + DevIo_SimpleWrite($hash, $msg, 2, !$nonl); +} + +sub +CUL_Attr(@) +{ + my ($cmd,$name,$aName,$aVal) = @_; + my $hash = $defs{$name}; + + if($aName eq "rfmode") { + + + $aVal = "SlowRF" if(!$aVal || + ($aVal ne "HomeMatic" + && $aVal ne "MAX" + && $aVal ne "WMBus_T" + && $aVal ne "WMBus_S" + && $aVal ne "KOPP_FC" + && $aVal ne "Betty")); + my $msg = $hash->{NAME} . ": Mode $aVal not supported"; + + if($aVal eq "HomeMatic") { + return if($hash->{initString} =~ m/Ar/); + if($hash->{CMDS} =~ m/A/ || IsDummy($hash->{NAME}) || !$hash->{FD}) { + $hash->{Clients} = $clientsHomeMatic; + $hash->{MatchList} = \%matchListHomeMatic; + CUL_SimpleWrite($hash, "Zx") if ($hash->{CMDS} =~ m/Z/); # reset Moritz + $hash->{initString} = "X21\nAr"; # X21 is needed for RSSI reporting + CUL_WriteInit($hash); + + } else { + Log3 $name, 2, $msg; + return $msg; + } + + } elsif($aVal eq "MAX") { + return if($hash->{initString} =~ m/Zr/); + if($hash->{CMDS} =~ m/Z/ || IsDummy($hash->{NAME}) || !$hash->{FD}) { + $hash->{Clients} = $clientsMAX; + $hash->{MatchList} = \%matchListMAX; + CUL_SimpleWrite($hash, "Ax") if ($hash->{CMDS} =~ m/A/); # reset AskSin + $hash->{initString} = "X21\nZr"; # X21 is needed for RSSI reporting + CUL_WriteInit($hash); + + } else { + Log3 $name, 2, $msg; + return $msg; + } + + } elsif($aVal eq "WMBus_S") { + return if($hash->{initString} =~ m/brs/); + if($hash->{CMDS} =~ m/b/ || IsDummy($hash->{NAME}) || !$hash->{FD}) { + $hash->{Clients} = $clientsWMBus; + $hash->{MatchList} = \%matchListWMBus; + $hash->{initString} = "X21\nbrs"; # Use S-Mode + CUL_WriteInit($hash); + + } else { + Log3 $name, 2, $msg; + return $msg; + } + } elsif($aVal eq "WMBus_T") { + return if($hash->{initString} =~ m/brt/); + if($hash->{CMDS} =~ m/b/ || IsDummy($hash->{NAME}) || !$hash->{FD}) { + $hash->{Clients} = $clientsWMBus; + $hash->{MatchList} = \%matchListWMBus; + $hash->{initString} = "X21\nbrt"; # Use T-Mode + CUL_WriteInit($hash); + + } else { + Log3 $name, 2, $msg; + return $msg; + } + } elsif($aVal eq "KOPP_FC") { + if($hash->{CMDS} =~ m/k/ || IsDummy($hash->{NAME}) || !$hash->{FD}) { + $hash->{Clients} = $clientsKOPP_FC; + $hash->{MatchList} = \%matchListKOPP_FC; + $hash->{initString} = "krS"; # krS: start Kopp receive Mode + CUL_WriteInit($hash); + + } else { + Log3 $name, 2, $msg; + return $msg; + } + + } elsif($aVal eq "Betty") { + if($hash->{CMDS} =~ m/y/ || IsDummy($hash->{NAME}) || !$hash->{FD}) { + $hash->{Clients} = $clientsBetty; + $hash->{MatchList} = \%matchListBetty; + $hash->{initString} = "X21\nyr"; # krS: start Betty receive Mode + CUL_WriteInit($hash); + + } else { + Log3 $name, 2, $msg; + return $msg; + } + + } else { + return if($hash->{initString} eq "X21"); + $hash->{Clients} = $clientsSlowRF; + $hash->{MatchList} = \%matchListSlowRF; + $hash->{initString} = "X21"; + CUL_SimpleWrite($hash, "Ax") if ($hash->{CMDS} =~ m/A/); # reset AskSin + CUL_SimpleWrite($hash, "Zx") if ($hash->{CMDS} =~ m/Z/); # reset Moritz + CUL_SimpleWrite($hash, "brx") if ($hash->{CMDS} =~ m/b/); # reset WMBus + CUL_WriteInit($hash); + + } + + Log3 $name, 2, "Switched $name rfmode to $aVal"; + delete $hash->{".clientArray"}; + + } elsif($aName eq "hmId"){ + if($cmd eq "set") { + return "wrong syntax: hmId must be 6-digit-hex-code (3 byte)" + if($aVal !~ m/^[A-F0-9]{6}$/i); + } + + } elsif($aName eq "connectCommand"){ + CUL_SimpleWrite($hash, $aVal) if($cmd eq "set"); + + } + + return undef; +} + +sub +CUL_prefix($$$) +{ + my ($isadd, $hash, $msg) = @_; + while($hash && $hash->{TYPE} !~ m/$culNameRe/) { + $msg = CallFn($hash->{NAME}, $isadd ? "AddPrefix":"DelPrefix", $hash, $msg); + $hash = $hash->{IODev}; + last if(!$hash); + } + return ($hash, $msg); +} + +1; + +=pod +=item summary connect devices with the culfw Firmware, e.g. Busware CUL +=item summary_DE Anbindung von Geraeten mit dem culfw Firmware, z.Bsp. Busware CUL +=begin html + + +

CUL

+
    + + + +
    + The CUL/CUN(O) is a family of RF devices sold by busware.de. + + With the opensource firmware + culfw they are capable + to receive and send different 433/868 MHz protocols (FS20/FHT/S300/EM/HMS/MAX!). + It is even possible to use these devices as range extenders/routers, see the + CUL_RFR module for details. +

    + + Some protocols (FS20, FHT and KS300) are converted by this module so that + the same logical device can be used, irrespective if the radio telegram is + received by a CUL or an FHZ device.
    + Other protocols (S300/EM) need their + own modules. E.g. S300 devices are processed by the CUL_WS module if the + signals are received by the CUL, similarly EMWZ/EMGZ/EMEM is handled by the + CUL_EM module.

    + + It is possible to attach more than one device in order to get better + reception, FHEM will filter out duplicate messages.

    + + Note: This module may require the Device::SerialPort or + Win32::SerialPort module if you attach the device via USB + and the OS sets strange default parameters for serial devices.

    + +
    + +
    + + + Define +
      + define <name> CUL <device> <FHTID>
      +
      + USB-connected devices (CUL/CUN):
        + <device> specifies the serial port to communicate with the CUL. + The name of the serial-device depends on your distribution, under + linux the cdc_acm kernel module is responsible, and usually a + /dev/ttyACM0 device will be created. If your distribution does not have a + cdc_acm module, you can force usbserial to handle the CUL by the + following command: +
          + modprobe usbserial vendor=0x03eb product=0x204b +
        + In this case the device is most probably /dev/ttyUSB0.

        + + You can also specify a baudrate if the device name contains the @ + character, e.g.: /dev/ttyACM0@38400

        + + If the baudrate is "directio" (e.g.: /dev/ttyACM0@directio), then the + perl module Device::SerialPort is not needed, and FHEM + opens the device with simple file io. This might work if the operating + system uses sane defaults for the serial parameters, e.g. some Linux + distributions and OSX.

        + +
      + Network-connected devices (CUN(O)):
        + <device> specifies the host:port of the device, e.g. + 192.168.0.244:2323 +
      +
      + If the device is called none, then no device will be opened, so you + can experiment without hardware attached.
      + + The FHTID is a 4 digit hex number, and it is used when the CUL talks to + FHT devices or when CUL requests data. Set it to 0000 to avoid answering + any FHT80b request by the CUL. +
    +
    + + + Set +
      +
    • reopen
      + Reopens the connection to the device and reinitializes it. +

    • +
    • raw
      + Issue a CUL firmware command. See the this document + for details on CUL commands. +

    • + +
    • freq / bWidth / rAmpl / sens
      + SlowRF mode only.
      + Set the CUL frequency / bandwidth / receiver-amplitude / sensitivity
      + + Use it with care, it may destroy your hardware and it even may be + illegal to do so. Note: The parameters used for RFR transmission are + not affected.
      +
        +
      • freq sets both the reception and transmission frequency. Note: + Although the CC1101 can be set to frequencies between 315 and 915 + MHz, the antenna interface and the antenna of the CUL is tuned for + exactly one frequency. Default is 868.3 MHz (or 433 MHz)
      • +
      • bWidth can be set to values between 58 kHz and 812 kHz. Large values + are susceptible to interference, but make possible to receive + inaccurately calibrated transmitters. It affects tranmission too. + Default is 325 kHz.
      • +
      • rAmpl is receiver amplification, with values between 24 and 42 dB. + Bigger values allow reception of weak signals. Default is 42. +
      • +
      • sens is the decision boundary between the on and off values, and it + is 4, 8, 12 or 16 dB. Smaller values allow reception of less clear + signals. Default is 4 dB.
      • +
      +

    • + +
    • hmPairForSec
      + HomeMatic mode only.
      + Set the CUL in Pairing-Mode for the given seconds. Any HM device set into + pairing mode in this time will be paired with FHEM. +

    • + +
    • hmPairSerial
      + HomeMatic mode only.
      + Try to pair with the given device. The argument is a 10 character + string, usually starting with letters and ending with digits, printed on + the backside of the device. It is not necessary to put the given device + in learning mode if it is a receiver. +

    • + +
    • led
      + Set the CUL led off (00), on (01) or blinking (02). +

    • +
    • ITClock
      + Set the IT clock for Intertechno V1 protocol. Default 250. +

    • +
    + + + Get +
      +
    • version
      + returns the CUL firmware version +

    • +
    • uptime
      + returns the CUL uptime (time since CUL reset) +

    • +
    • raw
      + Issues a CUL firmware command, and waits for one line of data returned by + the CUL. See the CUL firmware README document for details on CUL + commands. +

    • +
    • fhtbuf
      + CUL has a message buffer for the FHT. If the buffer is full, then newly + issued commands will be dropped, and an "EOB" message is issued to the + FHEM log. + fhtbuf returns the free memory in this buffer (in hex), + an empty buffer in the CUL V2 is 74 bytes, in CUL V3/CUN(O) 200 Bytes. + A message occupies 3 + 2x(number of FHT commands) bytes, + this is the second reason why sending multiple FHT commands with one + set is a good idea. The first reason is, that + these FHT commands are sent at once to the FHT. +

    • + +
    • ccconf
      + Read some CUL radio-chip (cc1101) registers (frequency, bandwidth, etc.), + and display them in human readable form. +

    • + +
    • cmds
      + Depending on the firmware installed, CULs have a different set of + possible commands. Please refer to the README of the firmware of your + CUL to interpret the response of this command. See also the raw command. +

    • +
    • credit10ms
      + One may send for a duration of credit10ms*10 ms before the send limit + is reached and a LOVF is generated. +

    • +
    + + + Attributes +
      +
    • addvaltrigger
      + Create triggers for additional device values. Right now these are RSSI + and RAWMSG for the CUL family and RAWMSG for the FHZ. +

    • + +
    • connectCommand
      + raw culfw command sent to the CUL after a (re-)connect of the USB device, + and sending the usual initialization needed for the configured rfmode. +
    • + +
    • do_not_notify
    • +
    • dummy
    • +
    • hmId
      + Set the HomeMatic ID of this device. If this attribute is absent, the + ID will be F1<FHTID>. Note 1: After setting or changing this + attribute you have to relearn all your HomeMatic devices. Note 2: The + value must be a 6 digit hex number, and 000000 is not valid. FHEM + won't complain if it is not correct, but the communication won't work. +

    • + +
    • hmProtocolEvents
      + Generate events for HomeMatic protocol messages. These are normally + used for debugging, by activating "inform timer" in a telnet session, + or looking at the Event Monitor window in the FHEMWEB frontend.
      + Example: +
        + + 2012-05-17 09:44:22.515 CUL CULHM RCV L:0B N:81 CMD:A258 SRC:...... + DST:...... 0000 (TYPE=88,WAKEMEUP,BIDI,RPTEN) + +
      +

    • + +
    • longids
      + Comma separated list of device-types for CUL that should be handled + using long IDs. This additional ID allows it to differentiate some + weather sensors, if they are sending on the same channel. + Therefore a random generated id is added. If you choose to use longids, + then you'll have to define a different device after battery change. + Default is not to use long IDs.
      + Modules which are using this functionality are for e.g. : + 14_Hideki, 41_OREGON, 14_CUL_TCM97001, 14_SD_WS07.
      + + Examples:
      +
        + # Do not use any long IDs for any devices (this is default):
        + attr cul longids 0
        + # Use long IDs for all devices:
        + attr cul longids 1
        + # Use longids for SD_WS07 devices.
        + # Will generate devices names like SD_WS07_TH_3 for channel 3.
        + attr cul longids SD_WS07 +
      +

    • + +
    • model (CUL,CUN,etc)
    • +
    • sendpool
      + If using more than one CUL for covering a large area, sending + different events by the different CUL's might disturb each other. This + phenomenon is also known as the Palm-Beach-Resort effect. + Putting them in a common sendpool will serialize sending the events. + E.g. if you have three CUN's, you have to specify following + attributes:
      + attr CUN1 sendpool CUN1,CUN2,CUN3
      + attr CUN2 sendpool CUN1,CUN2,CUN3
      + attr CUN3 sendpool CUN1,CUN2,CUN3

      +

    • +
    • rfmode
      + Configure the RF Transceiver of the CUL (the CC1101). Available + arguments are: +
        +
      • SlowRF
        + To communicate with FS20/FHT/HMS/EM1010/S300/Hoermann devices @1 kHz + datarate. This is the default.
      • + +
      • HomeMatic
        + To communicate with HomeMatic type of devices @10 kHz datarate.
      • + +
      • MAX
        + To communicate with MAX! type of devices @10 kHz datarate.
      • + +
      • WMBus_S
      • +
      • WMBus_T
        + To communicate with Wireless M-Bus devices like water, gas or + electrical meters. Wireless M-Bus uses two different communication + modes, S-Mode and T-Mode. While in this mode, no reception of other + protocols like SlowRF or HomeMatic is possible. See also the WMBUS + FHEM Module. +
      • +
      +

    • +
    • showtime
    • + + +
    • readingFnAttributes
    • +
    +
    +
+ +=end html + +=begin html_DE + + +

CUL

+
    + + + +
    + Der CUL/CUN(O) ist eine Familie von Funkempfängern, die von der Firma + Busware verkauft wird. + + Mit der OpenSource Firmware + culfw können sie verschiedene + 868 MHz Funkprotokolle empfangen bzw. senden (FS20/FHT/S300/EM/HMS/MAX!). + Man kann diese Geräte auch zur Reichweitenverlängerung, siehe + CUL_RFR einsetzen. +

    + + Einige Protokolle (FS20, FHT und KS300) werden von diesem Modul in das FHZ + Format konvertiert, daher kann dasselbe logische Gerät verwendet werden, + egal ob das Funktelegramm von einem CUL oder einem FHZ Gerät empfangen + wird.
    + + Andere Protokolle (S300/EM) benötigen ihre eigenen Module. S300 + Geräte werden vom Modul CUL_WS verarbeitet, wenn das Signal von einem + CUL empfangen wurde, ähnliches gilt für EMWZ/EMGZ/EMEM: diese + werden vom CUL_EM Modul verarbeitet.

    + + Es ist möglich mehr als ein Gerät zu verwenden, um einen besseren + Empfang zu erhalten, FHEM filtert doppelte Funktelegramme aus.

    + + Bemerkung: Dieses Modul benötigt unter Umständen das + Device::SerialPort bzw. Win32::SerialPort Modul, + wenn Sie das Gerät über USB anschließen und das + Betriebssystem unübliche Parameter für serielle Schnittstellen + setzt.

    + +
    + +
    + + + Define +
      + define <name> CUL <device> <FHTID>
      +
      + Geräte, die an USB angeschlossen sind (CUL/CUN):
      +
        + <device> gibt die serielle Schnittstelle an, mit der der CUL + kommuniziert. Der Name der seriellen Schnittstelle hängt von der + gewählten Distribution und USB-Treiber ab, unter Linux ist dies das + Kernel Modul cdc_acm und üblicherweise wird die Schnittstelle + /dev/ttyACM0 genannt. Wenn die Linux Distribution über kein Kernel + Modul cdc_acm verfügt, dann kann die Schnittstelle über + usbserial mit dem folgenden Befehl erzeugt werden: +
          + modprobe usbserial vendor=0x03eb product=0x204b +
        + In diesem Fall ist diese Schnittstelle dann wahrscheinlich + /dev/ttyUSB0.

        + + Wenn der Name der Schnittstelle ein @ enthält, kann nachfolgend die + verwendete Baudrate angegeben werden, z.B.: /dev/ttyACM0@38400.

        + + Wenn die Baudrate mit "directio" angegeben wird (z.B.: + /dev/ttyACM0@directio), wird das Perl Modul + Device::SerialPort nicht benötigt und FHEM öffnet + die Schnittstelle mit einfachem Dateizugriff. Dies sollte dann + funktionieren, wenn das Betriebssystem vernünftige Standardwerte + für die serielle Schnittstelle verwendet, wie z.B. einige Linux + Distributionen oder OSX.

        +
      + + Geräte, die mit dem Netzwerk verbunden sind (CUN(O)):
      +
        + <device> gibt die Hostadresse:Port des Gerätes an, z.B. + 192.168.0.244:2323 +
      +
      + + Wenn das Gerät mit none bezeichnet wird, wird keine Schnittstelle + geöffnet und man kann ohne angeschlossene Hardware + experimentieren.
      + + Die FHTID ist eine 4-stellige hexadezimale Zahl und wird verwendet, wenn + der CUL FHT Telegramme sendet bzw. Daten anfragt. Diese sollte als 0000 + gewählt werden, wenn man FHT80b Anfragen durch den CUL vermeiden will. +
    +
    + + + Set +
      +
    • reopen
      + Öffnet die Verbindung zum Gerät neu und initialisiert es. +

    • +
    • raw
      + Sendet einen CUL Firmware Befehl. Siehe auch + hier für + nähere Erläuterungen der CUL Befehle. +

    • + +
    • freq / bWidth / rAmpl / sens
      + Nur in der Betriebsart SlowRF.
      Bestimmt die + CUL Frequenz / Bandbreite / Empfänger Amplitude / + Empfindlichkeit
      + + Bitte mit Vorsicht verwenden, da es die verwendete Hardware + zerstören kann bzw. es zu illegalen Funkzuständen kommen + kann.
      Bemerkung: Die Parameter für die RFR Übermittlung + werden hierdurch nicht beeinflußt.
      +
        +
      • freq bestimmt sowohl die Empfangs- als auch die Sendefrequenz.
        + Bemerkung: Auch wenn der CC1101 zwischen den Frequenzen 315 und 915 + MHz eingestellt werden kann, ist die Antennenanbindung bzw. die + Antenne des CUL exakt auf eine Frequenz eingestellt. Standard ist + 868.3 MHz (bzw. 433 MHz).
      • + +
      • bWidth kann zwischen 58 kHz und 812 kHz variiert werden. + Große Werte sind empfindlicher gegen Interferencen, aber + machen es möglich, nicht genau kalbrierte Signale zu + empfangen. Die Einstellung beeinflusst ebenso die Übertragung. + Standardwert ist 325 kHz.
      • + +
      • rAmpl ist die Verstärkung des Empfängers mit Werten + zwischen 24 and 42 dB. Größere Werte erlauben den + Empfang von schwachen Signalen. Standardwert ist 42.
      • + +
      • sens ist die Entscheidungsgrenze zwischen "on" und "off" + Zuständen und kann 4, 8, 12 oder 16 dB sein. Kleinere Werte + erlauben den Empfang von undeutlicheren Signalen. Standard ist 4 + dB.
      • +
      +

    • + +
    • hmPairForSec
      + Nur in der Betriebsart HomeMatic.
      Versetzt den + CUL für die angegebene Zeit in Sekunden in den Anlern-Modus. Jedes + HM Gerät, das sich im Anlern-Modus befindet, wird an FHEM + angelernt.

    • + + +
    • hmPairSerial
      + Nur in der Betriebsart HomeMatic.
      + Versucht, das angegebene Gerät anzulernen (zu "pairen"). Der + Parameter ist eine 10-stellige Zeichenfolge, die normalerweise mit + Buchstaben beginnt und mit Ziffern endet; diese sind auf der + Rückseite der Geräte aufgedruckt. Wenn das Gerät ein + Empfänger ist, ist es nicht notwendig, das angegebene Gerät in + den Anlern-Modus zu versetzen.

    • + + +
    • led
      + Schaltet die LED des CUL: aus (00), an (01) oder blinkend (02). +

    • +
    • ITClock
      + Setzt die IT clock fü Intertechno V1 Protokoll. Default 250. +

    • +
    + + + Get +
      +
    • version
      + gibt die Version der CUL Firmware zurück +

    • +
    • uptime
      + gibt die Betriebszeit des CULs zurück (Zeit seit dem letzten Reset + des CULs)

    • + +
    • raw
      + Sendet einen CUL Firmware Befehl und wartet auf eine Rückgabe des + CULs. Siehe auch README der Firmware für nähere + Erläuterungen zu den CUL Befehlen.

    • + +
    • fhtbuf
      + Der CUL hat einen Puffer für Nachrichten für FHT. Wenn der + Puffer voll ist, werden neu empfangene Telegramme ignoriert und eine + "EOB" Meldung wird in die FHEM Logdatei geschrieben. + + fhtbuf gibt den freien Speicher dieses Puffers (in hex) + zurück, ein leerer Puffer im CUL V2 hat 74 Byte, im CUL V3/CUN(O) + hat 200 Byte. Eine Telegramm benötigt 3 + 2x(Anzahl der FHT + Befehle) Byte, dies ist ein Grund, warum man mehrere FHT Befehle mit + einem set senden sollte. Ein weiterer Grund ist, + dass diese FHT Befehle in einem "Paket" zum FHT Gerät gesendet werden. +

    • + +
    • ccconf
      + Liest einige CUL Register des CC1101 (Sende- und Empfängerchips) + aus (Frequenz, Bandbreite, etc.) und stellt diese in lesbarer Form dar. +

    • + +
    • cmds
      + In abhägigkeit der installierten Firmware hat der CUL/CUN(O) + unterschiedliche Befehlssätze. Nähere Informationen über + die Befehle bzw. deren Interpretation siehe README Datei der + verwendeten CUL Firmware. Siehe auch Anmerkungen beim raw Befehl. +

    • + +
    • credit10ms
      + Der Funkraum darf für eine Dauer von credit10ms*10 ms belegt + werden, bevor die gesetzliche 1% Grenze erreicht ist und eine + LOVF Meldung ausgegeben wird.

    + + + Attribute +
      +
    • addvaltrigger
      + Generiert Trigger für zusätzliche Werte. Momentan sind dies + RSSI und RAWMSG für die CUL Familie und RAWMSG für FHZ. +

    • + +
    • connectCommand
      + culfw Befehl, was nach dem Verbindungsaufbau mit dem USB-Gerät, nach + Senden der zum Initialisieren der konfigurierten rfmode benötigten + Befehle gesendet wird. +
    • + +
    • do_not_notify
    • +
    • dummy
    • + +
    • hmId
      + Setzt die HomeMatic ID des Gerätes. Wenn dieses Attribut fehlt, + wird die ID zu F1<FHTID> gesetzt. Bemerkung 1: Nach dem Setzen + bzw. Verändern dieses Attributes müssen alle HomeMatic + Geräte neu angelernt werden. Bemerkung 2: Der Wert muss + eine 6-stellige Hexadezimalzahl sein, 000000 ist ungültig. FHEM + überprüft nicht, ob die ID korrekt ist, im Zweifelsfall + funktioniert die Kommunikation nicht.

    • + +
    • hmProtocolEvents
      + Generiert Ereignisse für HomeMatic Telegramme. Diese werden + normalerweise für die Fehlersuche verwendet, z.B. durch Aktivieren + von inform timer in einer telnet Sitzung bzw. im + Event Monitor Fenster im FHEMWEB Frontend.
      + Beispiel: +
        + + 2012-05-17 09:44:22.515 CUL CULHM RCV L:0B N:81 CMD:A258 SRC:...... + DST:...... 0000 (TYPE=88,WAKEMEUP,BIDI,RPTEN) + +
      +

    • + +
    • longids
      + Durch Kommata getrennte Liste von Device-Typen für Empfang von + langen IDs mit den CUL. Diese zusätzliche ID erlaubt es + Wettersensoren, welche auf dem gleichen Kanal senden zu unterscheiden. + Hierzu wird eine zufällig generierte ID hinzugefügt. Wenn Sie + longids verwenden, dann wird in den meisten Fällen nach einem + Batteriewechsel ein neuer Sensor angelegt. + Standardmäßig werden keine langen IDs verwendet.
      + Folgende Module verwenden diese Funktionalität: + 14_Hideki, 41_OREGON, 14_CUL_TCM97001, 14_SD_WS07.
      + Beispiele: +
        + # Keine langen IDs verwenden (Default Einstellung):
        + attr cul longids 0
        + # Immer lange IDs verwenden:
        + attr cul longids 1
        + # Verwende lange IDs für SD_WS07 Devices.
        + # Device Namen sehen z.B. so aus: SD_WS07_TH_3 for channel 3.
        + attr cul longids SD_WS07 +
      +

    • + +
    • model (CUL,CUN)

    • + +
    • rfmode
      + Konfiguriert den RF Transceiver des CULs (CC1101). Verfügbare + Argumente sind: +
        +
      • SlowRF
        + Für die Kommunikation mit FS20/FHT/HMS/EM1010/S300/Hoermann + Geräten @1 kHz Datenrate (Standardeinstellung).
      • + +
      • HomeMatic
        + Für die Kommunikation mit HomeMatic Geräten @10 kHz + Datenrate.
      • + +
      • MAX
        + Für die Kommunikation mit MAX! Geräten @10 kHz + Datenrate.
      • +
      • WMBus_S
      • +
      • WMBus_T
        + Für die Kommunikation mit Wireless M-Bus Geräten wie + Wasser-, Gas- oder Elektrozählern. Wireless M-Bus verwendet + zwei unterschiedliche Kommunikationsarten, S-Mode und T-Mode. In + diesem Modus ist der Empfang von anderen Protokollen wie SlowRF + oder HomeMatic nicht möglich.
      • +
      +

    • + +
    • sendpool
      + Wenn mehr als ein CUL verwendet wird, um einen größeren + Bereich abzudecken, können diese sich gegenseitig + beeinflussen. Dieses Phänomen wird auch Palm-Beach-Resort Effekt + genannt. Wenn man diese zu einen gemeinsamen Sende"pool" + zusammenschließt, wird das Senden der einzelnen Telegramme + seriell (d.h. hintereinander) durchgeführt. + Wenn z.B. drei CUN's zur + Verfügung stehen, werden folgende Attribute gesetzt:
      + attr CUN1 sendpool CUN1,CUN2,CUN3
      + attr CUN2 sendpool CUN1,CUN2,CUN3
      + attr CUN3 sendpool CUN1,CUN2,CUN3

      +

    • + +
    • showtime
    • +
    • readingFnAttributes
    • +
    +
    +
+ +=end html_DE +=cut diff --git a/FHEM/10_Betty.pm b/FHEM/10_Betty.pm new file mode 100644 index 0000000..9fe6b47 --- /dev/null +++ b/FHEM/10_Betty.pm @@ -0,0 +1,176 @@ +############################################## +# $Id: $ +package main; + +use strict; +use warnings; +use SetExtensions; + +my %sets = ( + "clear:noArg" => "", + "time:noArg" => "", + "raw" => "", +); + +sub +Betty_Initialize($) +{ + my ($hash) = @_; + + + $hash->{Match} = "^y.*"; + $hash->{SetFn} = "Betty_Set"; + $hash->{DefFn} = "Betty_Define"; + $hash->{ParseFn} = "Betty_Parse"; + $hash->{AttrList} = "IODev ". $readingFnAttributes; +} + + + +################################### +sub +Betty_Set($@) { + my ($hash, @a) = @_; + + return "set $hash->{NAME} needs at least one parameter" if(@a < 2); + + my $me = shift @a; + my $cmd = shift @a; + my $arg = shift @a; + my $arg2 = shift @a; + + return join(" ", sort keys %sets) if ($cmd eq "?"); + + if ($cmd eq "clear") { + my @cH = ($hash); + delete $_->{READINGS} foreach (@cH); + return undef; + + } elsif ($cmd eq "raw") { + my $msg = $arg; + #IOWrite( $hash, $msg ); + IOWrite( $hash, "y", $msg ); + return undef; + + } elsif ($cmd eq "time") { + my $address = $hash->{ADDRESS}; + + my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime; + + my $m = sprintf("%02d%02d%02d%02d",$mday,$wday,$month+1, $year-100); + my $n = sprintf("%02d%02d%02d",$sec, $min, $hour ); + + my $msg = "w".$address; + IOWrite( $hash, "y", $msg ); + $msg = "s0a".$address."0003".$m.$n; + IOWrite( $hash, "y", $msg ); + + return undef; + + } + + return "Unknown argument $cmd, choose one of ". join(" ", sort keys %sets); +} + + +############################# +sub +Betty_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + + return "wrong syntax: define Betty
" + if(int(@a) < 2 || int(@a) > 4); + + my $address = uc($a[2]); + $hash->{ADDRESS} = $address; + $modules{Betty}{defptr}{$address} = $hash; + AssignIoPort($hash); + + readingsSingleUpdate($hash, "state", "Initialized", 1); + + return undef; +} + + +sub +Betty_Parse($$) +{ + my ($hash,$msg) = @_; + + my ($len,$dest,$src,$service,$data) = unpack 'x1A2A2A2A2A*',$msg; + + my $def = $modules{Betty}{defptr}{$src}; + + if(!$def) { + DoTrigger("global","UNDEFINED Betty_$src Betty $src"); + $def = $modules{Betty}{defptr}{$src}; + if(!$def) { + Log3 $hash, 1, "Betty UNDEFINED, address $src"; + return "UNDEFINED Betty_$src Betty $src"; + } + } + + $hash = $def; + my $name = $hash->{NAME}; + + # packet_RFenc + if ($service eq '04') { + my ($addr,$key) = unpack 'A2A2',$data; + + if($hash->{helper}{lastkey } ne $key) { + $hash->{helper}{lastkey } = $key; + $key = sprintf "%02x", hex($key) & 0x7F; + readingsSingleUpdate($hash, "key", $addr."_".$key , 1); + } + + + # packet_test + } elsif ($service eq '01') { + + $data = latin1ToUtf8(pack("H*",$data)); + readingsSingleUpdate($hash, "test", $data , 1); + + # packet_time + } elsif ($service eq '03') { + + my ($request) = unpack 'A2',$data; + + if($request eq "FF") { + my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime; + + my $m = sprintf("%02d%02d%02d%02d",$mday,$wday,$month+1, $year-100); + my $n = sprintf("%02d%02d%02d",$sec, $min, $hour ); + + $msg = "s0a".$src."0003".$m.$n; + IOWrite( $hash, "y", $msg ); + } + + } else { + Log3 $hash, 4, "Betty UNKNOWN MESSAGE $service: $data"; + } + + return $name; +} + + + + +1; + +=pod +=item summary devices communicating with the Betty remote control +=item summary_DE Anbindung der Betty Fernbedienung +=begin html + + +

Betty

+
    + Todo +
+ +=end html + + +=cut diff --git a/boop/Makefile b/boop/Makefile index 8a4eaf4..1f49ca1 100644 --- a/boop/Makefile +++ b/boop/Makefile @@ -55,7 +55,7 @@ ifeq ($(MAKECMDGOALS),debug) COMPILE += -D DEBUGMODE OPTFLAGS = -O0 else - OPTFLAGS = -Os + OPTFLAGS = -Og endif ifeq ($(MAKECMDGOALS),release) diff --git a/boop/audio/sid.c b/boop/audio/sid.c index 0128d39..9ade33e 100644 --- a/boop/audio/sid.c +++ b/boop/audio/sid.c @@ -157,7 +157,7 @@ void beep(unsigned char n) { SIDsetfrq(0,5001); break; } - PWMPR = 0; + //PWMPR = 0; switchSound(SOUND_ON); SID.flags |= SIDenable; SID.reg[REG_Control] |= GATE; diff --git a/boop/audio/sid.h b/boop/audio/sid.h index e67980f..05833b5 100644 --- a/boop/audio/sid.h +++ b/boop/audio/sid.h @@ -101,12 +101,12 @@ struct SID_ { struct SID_ SID; -unsigned int playtone_cb; -unsigned char *playtone[3]; -unsigned char playstate; -unsigned char tonelen[3]; -unsigned short playcounter; -unsigned short playcountermax; +extern unsigned int playtone_cb; +extern unsigned char *playtone[3]; +extern unsigned char playstate; +extern unsigned char tonelen[3]; +extern unsigned short playcounter; +extern unsigned short playcountermax; void SIDsetfrq(unsigned char voice, unsigned short frq); void SIDsetadsr(unsigned char voice,unsigned char attack, unsigned char decay, unsigned char sustain, unsigned char release); diff --git a/boop/audio/sidfiles.h b/boop/audio/sidfiles.h index 0a4dccb..6f10dde 100644 --- a/boop/audio/sidfiles.h +++ b/boop/audio/sidfiles.h @@ -769,6 +769,7 @@ const unsigned char song1[] = { 0xa2,0x25,0x00,0x00,0x21,0x11,0x70,0xd2,0x0f,0x00,0x00,0x21,0x00,0x70, 0xa2,0x25,0x00,0x00,0x21,0x11,0x70,0xd2,0x0f,0x00,0x00,0x21,0x00,0x70, 0xa2,0x25,0x00,0x00,0x21,0x11,0x70,0xd2,0x0f,0x00,0x00,0x21,0x00,0x70, +/* 0x1f,0x15,0x00,0x00,0x21,0x11,0x70,0xc3,0x10,0x00,0x00,0x21,0x00,0x70, 0x1f,0x15,0x00,0x00,0x21,0x11,0x70,0xc3,0x10,0x00,0x00,0x21,0x00,0x70, 0x1f,0x15,0x00,0x00,0x21,0x11,0x70,0xc3,0x10,0x00,0x00,0x21,0x00,0x70, @@ -1001,4 +1002,5 @@ const unsigned char song1[] = { 0xc1,0x2c,0x00,0x00,0x21,0x11,0x70,0x31,0x1c,0x00,0x00,0x21,0x00,0x70, 0xc1,0x2c,0x00,0x00,0x21,0x11,0x70,0x31,0x1c,0x00,0x00,0x21,0x00,0x70, 0xc1,0x2c,0x00,0x00,0x21,0x11,0x70,0x31,0x1c,0x00,0x00,0x21,0x00,0x70 +*/ }; diff --git a/boop/audio/sound.c b/boop/audio/sound.c index 310ecbc..3eee98c 100644 --- a/boop/audio/sound.c +++ b/boop/audio/sound.c @@ -20,6 +20,7 @@ #include "sound.h" #include "soundirq.h" #include "lpc2220.h" +#include "pwm.h" #define AUTO_OFF_TIME 0x4000 @@ -37,7 +38,7 @@ unsigned char timeout; unsigned int auto_timeout; void startSoundIRQ(void) -{ +{/* timeout = 0; auto_timeout = 0; out1 = 0; @@ -57,6 +58,7 @@ void startSoundIRQ(void) //VICVectCntl0 = VIC_SLOT_EN | INT_SRC_PWM; VICIntSelect |= INT_PWM; VICIntEnable = INT_PWM; + */ } void initSound(void) @@ -67,12 +69,18 @@ void initSound(void) tval = 0; last_sample = 0; bl_val = 0x3F; + timeout = 0; + auto_timeout = 0; + out1 = 0; } void switchSound(unsigned char onoff) { if(onoff) { + + PWM_set_frequency(30864); + sound_shutdown = 0; PINSEL0 &= ~(3 << (2 * SND_PWM)); // IO PINSEL0 |= (2 << (2 * SND_PWM)); // PWM @@ -81,6 +89,7 @@ void switchSound(unsigned char onoff) FIODIR0 |= (1<= 63) - { - FIODIR0 |= (1<<4); // sck0/P0.4 - cmp_val -= 63; - } - else - { - FIODIR0 &= ~(1<<4); // sck0/P0.4 - } - } diff --git a/boop/betty.cfg b/boop/betty.cfg index 4ac8704..ba49750 100644 --- a/boop/betty.cfg +++ b/boop/betty.cfg @@ -71,9 +71,9 @@ proc betty_init { } { # Memory Bank Configuration # BCFG0: 16bit, rble, 2wst - 30 mhz : Betty: FLASH 0 @ 0x80000000 - mww 0xffe00000 0x10000420 + mww 0xffe00000 0x10001CA0 # BCFG2: 16bit, rble, 2wst - 30 mhz : Betty: FLASH 1 @ 0x82000000 - mww 0xffe00008 0x10000420 + mww 0xffe00008 0x10001CA0 # BCFG1: 8 bit, 3 sram wst, rble, 5 wst 3 idcy : Betty: LCD @ 0x81000000 mww 0xffe00004 0x00000400 @@ -108,8 +108,8 @@ proc flash_boop {IMAGE} { flash erase_check 0 flash erase_sector 0 0 last flash erase_check 0 - flash write_bank 0 $IMAGE 0 - reset run + flash write_bank 0 $IMAGE 0 + reset run } proc start_debug {} { diff --git a/boop/boop_rom.bin b/boop/boop_rom.bin index 1ffe406..33ec32b 100644 Binary files a/boop/boop_rom.bin and b/boop/boop_rom.bin differ diff --git a/boop/cc1100/cc1100.c b/boop/cc1100/cc1100.c index 4874ca2..02b9c80 100644 --- a/boop/cc1100/cc1100.c +++ b/boop/cc1100/cc1100.c @@ -26,58 +26,74 @@ #include "cc1100.h" #include "irq.h" -//setting 6_WOR -const unsigned char conf[0x2F] = { - 0x29, // IOCFG2 - 0x2E, // IOCFG1 - 0x06, // IOCFG0 - 0x47, // FIFOTHR - 0xD3, // SYNC1 - 0x91, // SYNC0 - 0x3E, // PKTLEN - 0x1A, // PKTCTRL1 - 0x45, // PKTCTRL0 - 0x01, // ADDR - 0x01, // CHANNR - 0x06, // FSCTRL1 - 0x00, // FSCTRL0 - 0x10, // FREQ2 # - 0x0B, // FREQ1 # - 0xDA, // FREQ0 # -> 433,249969 MHz - 0x8A, // MDMCFG4 - 0x75, // MDMCFG3 - 0x13, // MDMCFG2 - 0x22, // MDMCFG1 - 0xC1, // MDMCFG0 CHANSPC_M - 0x35, // DEVIATN - 0x04, // MCSM2 - 0x0C, // MCSM1 0c - 0x38, // MCSM0 - 0x16, // FOCCFG - 0x6C, // BSCFG - 0x43, // AGCCTRL2 - 0x40, // AGCCTRL1 - 0x91, // AGCCTRL0 - 0x46, // WOREVT1 - 0x50, // WOREVT0 - 0x78, // WORCTRL - 0x56, // FREND1 - 0x10, // FREND0 - 0xA9, // FSCAL3 - 0x0A, // FSCAL2 - 0x00, // FSCAL1 - 0x11, // FSCAL0 - 0x41, // RCCTRL1 - 0x00, // RCCTRL0 - 0x57, // FSTEST - 0x7F, // PTEST - 0x3F, // AGCTEST - 0x98, // TEST2 - 0x31, // TEST1 - 0x0B // TEST0 +// Deviation = 21.423340 +// Base frequency = 433.254913 +// Carrier frequency = 433.254913 +// Channel number = 0 +// Carrier frequency = 433.254913 +// Modulated = true +// Modulation format = GFSK +// Manchester enable = false +// Sync word qualifier mode = 30/32 sync word bits detected +// Preamble count = 4 +// Channel spacing = 184.982300 +// Carrier frequency = 433.254913 +// Data rate = 37.4908 +// RX filter BW = 210.937500 +// Data format = Normal mode +// CRC enable = true +// Whitening = false +// Device address = 1 +// Address config = Address check and 0 (0x00) broadcast +// CRC autoflush = true +// PA ramping = false +// TX power = 0 +// Rf settings for CC1101 +const unsigned char conf[] = { + 0x29, // IOCFG2 GDO2 Output Pin Configuration + 0x2E, // IOCFG1 GDO1 Output Pin Configuration + 0x06, // IOCFG0 GDO0 Output Pin Configuration + 0x47, // FIFOTHR RX FIFO and TX FIFO Thresholds + 0xD3, // SYNC1 Sync Word, High Byte + 0x91, // SYNC0 Sync Word, Low Byte + 0x3E, // PKTLEN Packet Length + 0x1A, // PKTCTRL1 Packet Automation Control + 0x05, // PKTCTRL0 Packet Automation Control + 0x01, // ADDR Device Address + 0x00, // CHANNR Channel Number + 0x06, // FSCTRL1 Frequency Synthesizer Control + 0x00, // FSCTRL0 Frequency Synthesizer Control + 0x10, // FREQ2 Frequency Control Word, High Byte + 0x0B, // FREQ1 Frequency Control Word, Middle Byte + 0xE6, // FREQ0 Frequency Control Word, Low Byte + 0x8A, // MDMCFG4 Modem Configuration + 0x6C, // MDMCFG3 Modem Configuration + 0x13, // MDMCFG2 Modem Configuration + 0x22, // MDMCFG1 Modem Configuration + 0xC1, // MDMCFG0 Modem Configuration + 0x35, // DEVIATN Modem Deviation Setting + 0x04, // MCSM2 Main Radio Control State Machine Configuration + 0x0C, // MCSM1 Main Radio Control State Machine Configuration + 0x38, // MCSM0 Main Radio Control State Machine Configuration + 0x16, // FOCCFG Frequency Offset Compensation Configuration + 0x6C, // BSCFG Bit Synchronization Configuration + 0x43, // AGCCTRL2 AGC Control + 0x40, // AGCCTRL1 AGC Control + 0x91, // AGCCTRL0 AGC Control + 0x46, // WOREVT1 High Byte Event0 Timeout + 0x50, // WOREVT0 Low Byte Event0 Timeout + 0x78, // WORCTRL Wake On Radio Control + 0x56, // FREND1 Front End RX Configuration + 0x10, // FREND0 Front End TX Configuration + 0xE9, // FSCAL3 Frequency Synthesizer Calibration + 0x2A, // FSCAL2 Frequency Synthesizer Calibration + 0x00, // FSCAL1 Frequency Synthesizer Calibration + 0x1F, // FSCAL0 Frequency Synthesizer Calibration + 0x41, // RCCTRL1 RC Oscillator Configuration + 0x00, // RCCTRL0 RC Oscillator Configuration }; -const unsigned char confasync[0x2F] = { +const unsigned char confasync[] = { 0x0D, // IOCFG2 0x0D, // IOCFG1 0x2E, // IOCFG0 @@ -120,12 +136,6 @@ const unsigned char confasync[0x2F] = { 0x1F, // FSCAL0 0x41, // RCCTRL1 0x00, // RCCTRL0 - 0x59, // FSTEST - 0x7F, // PTEST - 0x3F, // AGCTEST - 0x81, // TEST2 - 0x35, // TEST1 - 0x09 // TEST0 }; void cc1100_init(void) { @@ -164,7 +174,7 @@ void cc1100_init(void) { while (SSPSR & (1<<4)); xx = SSPDR; - cc1100_write((0x00 | BURST ),(unsigned char*)conf,0x2f); + cc1100_write((0x00 | BURST ),(unsigned char*)conf,sizeof(conf)); cc1100_write1(PATABLE,0xC0); cc1100_strobe(SIDLE); cc1100_strobe(SPWD); diff --git a/boop/cc1100/cc1100.h b/boop/cc1100/cc1100.h index 3e0b3c7..f4cc27a 100644 --- a/boop/cc1100/cc1100.h +++ b/boop/cc1100/cc1100.h @@ -118,8 +118,8 @@ #define MARCSTATE_IDLE 0x01 #define MARCSTATE_RX 0x0d -const unsigned char conf[0x2F] __attribute__((aligned(0x4))); -const unsigned char confasync[0x2F] __attribute__((aligned(0x4))); +extern const unsigned char conf[]; //__attribute__((aligned(0x4))); +extern const unsigned char confasync[];// __attribute__((aligned(0x4))); void cc1100_init(void); unsigned char cc1100_write(unsigned char addr, unsigned char* data, unsigned char length); diff --git a/boop/cc1100/rf.c b/boop/cc1100/rf.c index 62ce2e2..cc93c81 100644 --- a/boop/cc1100/rf.c +++ b/boop/cc1100/rf.c @@ -485,14 +485,14 @@ void RFasyncmode(unsigned char on) { RF_changestate(RFidle); while(RF.state != RFidle); stopRFIRQ(); - cc1100_write((0x00 | BURST ),(unsigned char*)confasync,0x2f); + cc1100_write((0x00 | BURST ),(unsigned char*)confasync,sizeof((unsigned char*)confasync)); cc1100_write1(PATABLE,0xf0); PINSEL1 &= 0xfffffffc; // GDO0 as GPIO FIODIR0 |= GDO0; // output } else { PINSEL1 |= 1; // GDO0 as EINT0 - cc1100_write((0x00 | BURST ),(unsigned char*)conf,0x2f); + cc1100_write((0x00 | BURST ),(unsigned char*)conf,sizeof((unsigned char*)conf)); cc1100_write1(PATABLE,0xC0); cc1100_strobe(SIDLE); load_RF_setting(); diff --git a/boop/crt.s b/boop/crt.s index 27636b6..34bf0dc 100644 --- a/boop/crt.s +++ b/boop/crt.s @@ -182,7 +182,7 @@ Reset_Handler: /* --+--+-+-+-+-+--------+-----+-------+-+---- */ /* ldr r1, =0x10000400 /* 00|01|0|0|0|0|00000000|00000|1|00000|0|0000 16bit, rble, 3wst - 10 mhz*/ /* ldr r1, =0x10000420 /* 00|01|0|0|0|0|00000000|00000|1|00001|0|0000 16bit, rble, 4wst - 30 mhz*/ - ldr r1, =0x100004A0 /* 00|01|0|0|0|0|00000000|00000|1|00101|0|0000 16bit, rble, 6wst - 60 mhz*/ + ldr r1, =0x10001CA0 /* 00|01|0|0|0|0|00000000|00101|1|00101|0|0000 16bit, rble, 6wst - 60 mhz*/ str r1,[r0] /* set bcfg0 (flash) */ str r1,[r0,#0x08] /* set bcfg2 (flash) */ diff --git a/boop/gui/testmenu.c b/boop/gui/testmenu.c index e5af164..ce4d331 100644 --- a/boop/gui/testmenu.c +++ b/boop/gui/testmenu.c @@ -29,6 +29,7 @@ #include "ir_selector.h" #include "infrared.h" #include "sid.h" +#include "sidfiles.h" #include "timerfuncs.h" #include "sound.h" #include "lpc2220.h" @@ -861,6 +862,35 @@ void test_RF(void) { cur_ep->bufferlen = 3; cur_ep->flags |= EPenabled | EPoutput | EPnewdata | EPonce | EPsendwor; + RF_changestate(RFtx); + } else if(KEY_1) + { + struct RFendpoint_* cur_ep; + + cur_ep = openEP(0,0, packet_test); + if(cur_ep) { + cur_ep->dest = destAddr; + cur_ep->data[0] = 'X'; + cur_ep->data[1] = '1'; + cur_ep->data[2] = 0x00; + cur_ep->bufferlen = 3; + cur_ep->flags |= EPenabled | EPoutput | EPnewdata | EPonce; + + RF_changestate(RFtx); + } + } + else if(KEY_2) + { + struct RFendpoint_* cur_ep; + + cur_ep = openEP(0,0, packet_test); + cur_ep->dest = destAddr; + cur_ep->data[0] = 'X'; + cur_ep->data[1] = '2'; + cur_ep->data[2] = 0x00; + cur_ep->bufferlen = 3; + cur_ep->flags |= EPenabled | EPoutput | EPnewdata | EPonce ; + RF_changestate(RFtx); } } @@ -934,6 +964,9 @@ void test_sid(void) { draw_string (0, 95, "color keys", LCD_COLOR_B, DRAW_PUT); draw_string (0, 104, "set waveform", LCD_COLOR_B, DRAW_PUT); + draw_string (0, 120, "Mute", LCD_COLOR_B, DRAW_PUT); + draw_string (0, 129, "Raiders March", LCD_COLOR_B, DRAW_PUT); + sysInfo |= SYS_IR; SID.noise = 0xaa; playstate = 0x00; @@ -1052,6 +1085,20 @@ void test_sid(void) { playtone_cb = addTimerCB(SIDplaytone, 4); startCB(playtone_cb); } + } else if (KEY_Mute) + { + if (playstate == 0) + { + playstate = 1; + + playtone[0] = (unsigned char*)&song1[0]; + + playcounter = 0; + playcountermax = sizeof(song1)/14; + + playtone_cb = addTimerCB(SIDplaydump, 4); + startCB(playtone_cb); + } } } while (!KEY_Exit); sysInfo &= ~SYS_IR; diff --git a/boop/infrared/Make.conf b/boop/infrared/Make.conf index 2a1fa32..f6aed17 100644 --- a/boop/infrared/Make.conf +++ b/boop/infrared/Make.conf @@ -1,5 +1,5 @@ -THUMBSRCS := infrared.c codes.c encoders.c ir_capture.c ir_selector.c -SRCS := infraredirq.c +THUMBSRCS := infrared.c codes.c encoders.c ir_capture.c ir_selector.c +SRCS := infraredirq.c pwm.c THUMBSRCSUNOPT := ir_itt.c ir_nrc17.c \ ir_raw.c ir_rc5.c ir_rc6.c ir_rca.c ir_rcmm.c ir_rec80.c ir_recs80.c ir_rf.c \ ir_sirc.c ir_spaceenc.c ir_lirc.c diff --git a/boop/infrared/codes.c b/boop/infrared/codes.c index f30c7ad..99a5f59 100644 --- a/boop/infrared/codes.c +++ b/boop/infrared/codes.c @@ -222,7 +222,7 @@ const struct TABLES_N RAW = const struct TABLES_L LIRC = { - 9, + 10, { { #include "ir_codes/lirc/ufs922" @@ -259,6 +259,10 @@ const struct TABLES_L LIRC = { #include "ir_codes/lirc/samsung_ue46b6000" "Samsung TV" - } + }, + { + #include "ir_codes/lirc/beo4" + "bang & olufsen" + } } }; diff --git a/boop/infrared/infrared.c b/boop/infrared/infrared.c index e0ac240..5e3aa45 100644 --- a/boop/infrared/infrared.c +++ b/boop/infrared/infrared.c @@ -25,6 +25,7 @@ #include "encoders.h" #include "codes.h" #include "ir_selector.h" +#include "pwm.h" volatile unsigned char mod_enable; volatile unsigned char hi_border; @@ -61,9 +62,9 @@ void startIrIRQ(void) // T1PR = 0x01; T1MCR = 0x03; - //VICVectAddr1 = (unsigned long)&(irIRQ); - //VICVectCntl1 = VIC_SLOT_EN | INT_SRC_TIMER1; - VICIntSelect |= INT_TIMER1; + VICVectAddr1 = (unsigned long)&(irIRQ); + VICVectCntl1 = VIC_SLOT_EN | INT_SRC_TIMER1; + //VICIntSelect |= INT_TIMER1; VICIntEnable = INT_TIMER1; } @@ -109,11 +110,21 @@ void defStopper(void) void runIR(void) { T1TCR = 0x01; + PWM_set_IR_duty_cycle(0); + +} + +void setIRspeed(struct irModule module) +{ + PWM_set_frequency(15000000 / (module.tval * module.lo_border)); + ir.duty_cycle =(module.hi_border * 100) / module.lo_border; } void stopIR(void) { T1TCR = 0x03; + PWM_set_IR_duty_cycle(0); + } void copyMapC(unsigned char *map) diff --git a/boop/infrared/infrared.h b/boop/infrared/infrared.h index b10991e..4e5665a 100644 --- a/boop/infrared/infrared.h +++ b/boop/infrared/infrared.h @@ -63,28 +63,8 @@ struct IR_VARS_ { unsigned long actpre_data; unsigned long post_data; // data which the remote sends after actual keycode unsigned long actpost_data; - unsigned short flags; // flags - unsigned short phead,shead; // header - unsigned short plead; // leading pulse - unsigned short ptrail; // trailing pulse - unsigned short pfoot,sfoot; // foot - unsigned short pre_p,pre_s; // signal between pre_data and keycode - unsigned short post_p,post_s; // signal between keycode and post_code - unsigned short gap; - unsigned short repeat_gap; - unsigned short prepeat,srepeat; - unsigned short cycles_counter; - unsigned char bits; // bits (length of code) - unsigned char pre_data_bits; // length of pre_data - unsigned char post_data_bits; // length of post_data - unsigned char rc6_bit; // doubles signal length of this bit (only used for RC-6) - unsigned char pthree,sthree; // 3 (only used for RC-MM) - unsigned char ptwo,stwo; // 2 (only used for RC-MM) - unsigned char pone,sone; // 1 - unsigned char pzero,szero; // 0 - unsigned char min_repeat; + unsigned long cycles_counter; unsigned char bit; - unsigned char map; unsigned char stop; unsigned char repeats; } lirc; @@ -93,11 +73,12 @@ struct IR_VARS_ { unsigned int actcmd; unsigned char toggle; unsigned char state; + unsigned char duty_cycle; } ir; //#define setIRspeed( _m ) { if(sysInfo & 0x80) T1MR0 = _m.tval1; else T1MR0 = _m.tval; } -#define setIRspeed( _m ) { T1MR0 = _m.tval; } +//#define setIRspeed( _m ) { T1MR0 = _m.tval; } void __attribute__ ((section(".text.fastcode"))) defIR(void); void defSender(unsigned long cmd); @@ -109,6 +90,7 @@ void startIrIRQ(void); void setIR(struct irModule module); void runIR(void); void stopIR(void); +void setIRspeed(struct irModule module); unsigned long setEncoder( unsigned char _x, unsigned char _y ); diff --git a/boop/infrared/infraredirq.c b/boop/infrared/infraredirq.c index 5fa7314..2ae58f8 100644 --- a/boop/infrared/infraredirq.c +++ b/boop/infrared/infraredirq.c @@ -23,9 +23,8 @@ #include "keyboard.h" #include "rf.h" #include "cc1100.h" +#include "pwm.h" -static unsigned int c_cnt = 0; -static unsigned int b_len = 0; extern volatile unsigned char mod_enable; extern volatile unsigned char hi_border; extern volatile unsigned char lo_border; @@ -35,33 +34,15 @@ extern ir_fn irEncoder; void __attribute__ ((section(".text.fastcode"))) irIRQ(void) { - c_cnt++; - if(c_cnt <= hi_border) - { - FIOSET0 = (mod_enable<<21); - } - else - { - FIOCLR0 = (1<<21); - if(c_cnt >= lo_border) - { - c_cnt = 0; - b_len++; - if(b_len >= cycles) - { - irEncoder(); - b_len = 0; - - if(!hi_border) { //RF mode - if(mod_enable) - FIOCLR0 = GDO0; - else - FIOSET0 = GDO0; - } - } - } + + irEncoder(); + + if(mod_enable) { + PWM_set_IR_duty_cycle(ir.duty_cycle); + } else { + PWM_set_IR_duty_cycle(0); } T1IR = 1; -// VICVectAddr = 0; + } diff --git a/boop/infrared/ir_codes/lirc/beo4 b/boop/infrared/ir_codes/lirc/beo4 new file mode 100644 index 0000000..9869987 --- /dev/null +++ b/boop/infrared/ir_codes/lirc/beo4 @@ -0,0 +1 @@ +/* infrared codes for bang & olufsen Copyright (C) 2017 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /*pre_data*/ 0x00000000, // 2. start bit /*post_data*/ 0x00000000, /*toggle_bit_mask*/ 0x00, /*gap*/ 18000, // final gap to prevent collision /*repeat_gap*/ 0, /*bits*/ 17, // last(4.) start bit logical low as first data bit ==> 1+16 data bits = 17 /*pre_data_bits*/ 1, // 2. start bit /*post_data_bits*/ 0, /*rc6_bit*/ 0, /*frequency*/ 455000, // regular freq is 455kHz but to get a valid result 454,5 is used /*flags*/ LIRC_BO, /*header*/ 200,3125, // 1. start bit /*three*/ 0,0, /*two*/ 0,0, /*one*/ 200,9375, /*zero*/ 200,3125, /*plead*/ 0, /*ptrail*/ 200, // stop bit /*foot*/ 0,0, /*pre*/ 200,15625, //3. start bit /*post*/ 200,12500, // post bit /*repeat*/ 0,0, /*min_repeat*/ 0, /*duty cycle*/ 30, { 0x0000, // A -> 0x0000, // B -> 0x0000, // C -> 0x0000, // D -> 0x0000, // Betty -> 0xB44B, // Exit -> Exit 0x06F9, // Up -> UP 0x8679, // Down -> Down 0xA659, // Left -> Left 0x46B9, // Right -> Right 0x16E9, // OK -> OK 0x0160, // Vol+ -> Vol+ 0x0164, // Vol- -> Vol- 0xF00F, // Mute -> Mute 0x48B7, // Prog+ -> Prog+ 0x48B7, // Prog- -> Prog- 0x0101, // 1 -> 1 0x0102, // 2 -> 2 0x609F, // 3 -> 3 0x10EF, // 4 -> 4 0x906F, // 5 -> 5 0x50AF, // 6 -> 6 0x30CF, // 7 -> 7 0xB04F, // 8 -> 8 0x708F, // 9 -> 9 0x8877, // 0 -> 0 0xF20D, // -/-- -> Guide 0x0181, // AV -> Source 0x0f0c, // Menu -> Menue 0xD22D, // PiP -> Tools 0x1AE5, // A/B -> Return 0x7C83, // 16:9 -> P.Size 0xF807, // Info -> Info 0xD629, // VTX1 -> Ch.List 0x0000, // VTX2 -> 0xC837, // VTX3 -> Pre-CH 0x6897, // Blue -> Blue 0xA857, // Yello -> Yellow 0x28D7, // Green -> Green 0x36C9, // Red -> Red 0xC23D, // TV -> TV/DTV 0x0f0C // Power -> Standby }, \ No newline at end of file diff --git a/boop/infrared/ir_itt.c b/boop/infrared/ir_itt.c index 6294cc4..1156947 100644 --- a/boop/infrared/ir_itt.c +++ b/boop/infrared/ir_itt.c @@ -126,6 +126,7 @@ void __attribute__ ((section(".text.fastcode"))) ITT_Encode (void) } break; } + T1MR0 = cycles * ITT2_Module.lo_border * ITT2_Module.tval; } void ITT_LoadMap(unsigned char map) diff --git a/boop/infrared/ir_lirc.c b/boop/infrared/ir_lirc.c index 7e34d60..2dc4204 100644 --- a/boop/infrared/ir_lirc.c +++ b/boop/infrared/ir_lirc.c @@ -25,18 +25,16 @@ #include "lcd.h" #include "rf.h" #include "cc1100.h" +#include "pwm.h" #include "global.h" extern volatile unsigned char mod_enable; extern volatile unsigned int cycles; -extern volatile unsigned long keyMap[42]; -/* -#define RAW_IDLE 0x00 -#define RAW_HI 0x01 -#define RAW_LO 0x02 -*/ +struct CODE_TABLE_L *lirctable; + +unsigned int prev_cycles; /* needed for handling of b&o specific protocol added MN2017325 */ #define LIRC_IDLE 0x00 #define LIRC_HEAD_P 0x01 @@ -73,7 +71,7 @@ const struct irModule LIRC_Module = unsigned char __attribute__ ((section(".text.fastcode"))) send_data (unsigned long data, unsigned char pulse) { - const unsigned char* bittimes[4] = {&(ir.lirc.pzero), &(ir.lirc.pone), &(ir.lirc.ptwo), &(ir.lirc.pthree)}; + const unsigned short* bittimes[4] = {&(lirctable->pzero), &(lirctable->pone), &(lirctable->ptwo), &(lirctable->pthree)}; unsigned char notpulse = 1; if(pulse) { @@ -112,7 +110,7 @@ unsigned char __attribute__ ((section(".text.fastcode"))) send_data (unsigned lo cycles = bittimes[0][notpulse]; mod_enable = pulse; } - if((ir.lirc.bit+1 == ir.lirc.rc6_bit)) + if((ir.lirc.bit+1 == lirctable->rc6_bit)) cycles <<= 1; } else { @@ -132,86 +130,97 @@ unsigned char __attribute__ ((section(".text.fastcode"))) send_data (unsigned lo } void __attribute__ ((section(".text.fastcode"))) LIRC_Encode (void) { - unsigned short gap; + unsigned long gap; ir.lirc.cycles_counter += cycles; switch(ir.state) { case LIRC_IDLE: - cycles = ir.lirc.pone; + cycles = lirctable->pone; mod_enable = 0; break; case LIRC_HEAD_P: ir.lirc.cycles_counter = 0; - if(has_header && (!ir.lirc.repeats || (!(ir.lirc.flags&LIRC_NO_HEAD_REP) && !has_repeat) || (ir.lirc.flags&LIRC_REPEAT_HEADER))) { // + if(has_header && (!ir.lirc.repeats || (!(lirctable->flags&LIRC_NO_HEAD_REP) && !has_repeat) || (lirctable->flags&LIRC_REPEAT_HEADER))) { // mod_enable = 1; - cycles = ir.lirc.phead; + cycles = lirctable->phead; ir.state++; break; case LIRC_HEAD_S: mod_enable = 0; - cycles = ir.lirc.shead; + cycles = lirctable->shead; ir.state++; break; } ir.state = LIRC_LEAD_P; case LIRC_LEAD_P: - if(ir.lirc.plead) { + if(lirctable->plead) { mod_enable = 1; - cycles = ir.lirc.plead; + cycles = lirctable->plead; ir.state++; break; } ir.state++; case LIRC_PRE_DAT_P: if(!has_repeat || !(ir.lirc.repeats)) { - if(ir.lirc.pre_data_bits) { + if(lirctable->pre_data_bits) { send_data(ir.lirc.pre_data,1); ir.state++; break; case LIRC_PRE_DAT_S: ir.lirc.pre_data <<= send_data(ir.lirc.pre_data,0); - if(ir.lirc.bit >= ir.lirc.pre_data_bits) + if(ir.lirc.bit >= lirctable->pre_data_bits) ir.state++; else ir.state--; break; case LIRC_PRE_P: - if(ir.lirc.pre_p && ir.lirc.pre_s) { + if(lirctable->pre_p && lirctable->pre_s) { mod_enable = 1; - cycles = ir.lirc.pre_p; + cycles = lirctable->pre_p; ir.state++; break; case LIRC_PRE_S: mod_enable = 0; - cycles = ir.lirc.pre_s; + cycles = lirctable->pre_s; ir.state++; break; } } - ir.state = LIRC_DATA_P; + ir.state = LIRC_DATA_P; + prev_cycles = 0; case LIRC_DATA_P: send_data(ir.cmd,1); ir.state++; break; case LIRC_DATA_S: ir.cmd <<= send_data(ir.cmd,0); - if(ir.lirc.bit >= ir.lirc.pre_data_bits + ir.lirc.bits) + /* handling for b&o specific protocol added MN2017325 + special r-bit coding, if current bit is equal previous bit */ + if(is_BO) { + if (prev_cycles == cycles) { + prev_cycles = cycles; + cycles = lirctable->szero * 2 ; + } else { + prev_cycles = cycles; + } + } + if(ir.lirc.bit >= lirctable->pre_data_bits + lirctable->bits) ir.state++; else ir.state--; break; case LIRC_POST_P: - if(ir.lirc.post_data_bits) { - if(ir.lirc.post_p && ir.lirc.post_s) { + if(lirctable->post_data_bits) { + if(lirctable->post_p && lirctable->post_s) { mod_enable = 1; - cycles = ir.lirc.post_p; + cycles = lirctable->post_p; ir.state++; break; case LIRC_POST_S: mod_enable = 0; - cycles = ir.lirc.post_s; + cycles = lirctable->post_s; ir.state++; break; } @@ -221,8 +230,8 @@ void __attribute__ ((section(".text.fastcode"))) LIRC_Encode (void) { ir.state++; break; case LIRC_POST_DAT_S: - ir.lirc.post_data <<= send_data(ir.lirc.post_data,0); - if(ir.lirc.bit >= ir.lirc.pre_data_bits + ir.lirc.bits +ir.lirc.post_data_bits) + ir.lirc.post_data <<= send_data(ir.lirc.post_data,0); + if(ir.lirc.bit >= lirctable->pre_data_bits + lirctable->bits + lirctable->post_data_bits) ir.state = LIRC_TRAIL_P; else ir.state--; @@ -233,33 +242,33 @@ void __attribute__ ((section(".text.fastcode"))) LIRC_Encode (void) { case LIRC_REPEAT_P: if(has_repeat && ir.lirc.repeats) { mod_enable = 1; - cycles = ir.lirc.prepeat; + cycles = lirctable->prepeat; ir.state++; break; case LIRC_REPEAT_S: mod_enable = 0; - cycles = ir.lirc.srepeat; + cycles = lirctable->srepeat; ir.state++; break; } ir.state = LIRC_TRAIL_P; case LIRC_TRAIL_P: - if(ir.lirc.ptrail) { + if(lirctable->ptrail) { mod_enable = 1; - cycles = ir.lirc.ptrail; + cycles = lirctable->ptrail; ir.state++; break; } ir.state++; case LIRC_FOOT_S: - if(has_foot && (!ir.lirc.repeats || !(ir.lirc.flags&LIRC_NO_FOOT_REP)) && (!has_repeat || !ir.lirc.repeats)) { + if(has_foot && (!ir.lirc.repeats || !(lirctable->flags&LIRC_NO_FOOT_REP)) && (!has_repeat || !ir.lirc.repeats)) { mod_enable = 0; - cycles = ir.lirc.sfoot; + cycles = lirctable->sfoot; ir.state++; break; case LIRC_FOOT_P: mod_enable = 1; - cycles = ir.lirc.pfoot; + cycles = lirctable->pfoot; ir.state++; break; } @@ -271,17 +280,17 @@ void __attribute__ ((section(".text.fastcode"))) LIRC_Encode (void) { ir.lirc.pre_data = ir.lirc.actpre_data; ir.lirc.post_data = ir.lirc.actpost_data; - if((ir.lirc.repeat_gap && has_repeat && ir.lirc.repeats) | (is_RF && (ir.lirc.repeats >= ir.lirc.min_repeat))) - gap = ir.lirc.repeat_gap; + if((lirctable->repeat_gap && has_repeat && ir.lirc.repeats) | (is_RF && (ir.lirc.repeats >= lirctable->min_repeat))) + gap = lirctable->repeat_gap; else - gap = ir.lirc.gap; + gap = lirctable->gap; if(is_const && (ir.lirc.cycles_counter < gap)) cycles = gap - ir.lirc.cycles_counter; else cycles = gap; - if((ir.lirc.repeats >= ir.lirc.min_repeat) && ir.lirc.stop) { + if((ir.lirc.repeats >= lirctable->min_repeat) && ir.lirc.stop) { ir.state = LIRC_IDLE; } else { @@ -290,12 +299,14 @@ void __attribute__ ((section(".text.fastcode"))) LIRC_Encode (void) { ir.state = LIRC_HEAD_P; } } + + T1MR0 = 15 * cycles; + } void LIRC_Init(unsigned char map) { unsigned long freq; - struct CODE_TABLE_L *lirctable; if(map < LIRC.num_tables) { @@ -305,90 +316,32 @@ void LIRC_Init(unsigned char map) setIR(LIRC_Module); if(lirctable->flags&LIRC_RF) { - hi_border = 0; - lo_border = 1; + ir.duty_cycle = 50; freq = 20000; } else { freq = lirctable->freq; if(!freq) freq = 38000; - - if(lirctable->duty_cycle == 0) { //default 50% - hi_border = 1; - lo_border = 2; - } - else if(lirctable->duty_cycle <= 25) { - hi_border = 1; - lo_border = 4; - } - else if(lirctable->duty_cycle <= 33) { - hi_border = 1; - lo_border = 3; - } - else if(lirctable->duty_cycle <= 50) { - hi_border = 1; - lo_border = 2; - } - else if(lirctable->duty_cycle <= 66) { - hi_border = 2; - lo_border = 3; - } - else { //75% - hi_border = 3; - lo_border = 4; + + ir.duty_cycle = lirctable->duty_cycle; + if(!lirctable->duty_cycle) { //default 50% + ir.duty_cycle = 50; } } - T1MR0 = 15000000 / (freq * lo_border); + PWM_set_frequency(freq); + + T1MR0 = 15000000 / (freq); - - ir.lirc.phead = (lirctable->phead * freq) / 1000000; - ir.lirc.shead = (lirctable->shead * freq) / 1000000; - - ir.lirc.plead = (lirctable->plead * freq) / 1000000; - ir.lirc.actpre_data = (lirctable->pre_data)<<(32-lirctable->pre_data_bits); - ir.lirc.pre_data_bits = lirctable->pre_data_bits; - ir.lirc.pre_p = (lirctable->pre_p * freq) / 1000000; - ir.lirc.pre_s = (lirctable->pre_s * freq) / 1000000; - - ir.lirc.post_p = (lirctable->post_p * freq) / 1000000; - ir.lirc.post_s = (lirctable->post_s * freq) / 1000000; ir.lirc.actpost_data = (lirctable->post_data)<<(32-lirctable->post_data_bits); - ir.lirc.post_data_bits = lirctable->post_data_bits; - - ir.lirc.ptrail = (lirctable->ptrail * freq) / 1000000; - - ir.lirc.pfoot = (lirctable->pfoot * freq) / 1000000; - ir.lirc.sfoot = (lirctable->sfoot * freq) / 1000000; - - ir.lirc.prepeat = (lirctable->prepeat * freq) / 1000000; - ir.lirc.srepeat = (lirctable->srepeat * freq) / 1000000; - - ir.lirc.pzero = (lirctable->pzero * freq) / 1000000; - ir.lirc.szero = (lirctable->szero * freq) / 1000000; - ir.lirc.pone = (lirctable->pone * freq) / 1000000; - ir.lirc.sone = (lirctable->sone * freq) / 1000000; - ir.lirc.ptwo = (lirctable->ptwo * freq) / 1000000; - ir.lirc.stwo = (lirctable->stwo * freq) / 1000000; - ir.lirc.pthree = (lirctable->pthree * freq) / 1000000; - ir.lirc.sthree = (lirctable->sthree * freq) / 1000000; - - ir.lirc.gap = (lirctable->gap * freq) / 1000000; - ir.lirc.repeat_gap = (lirctable->repeat_gap * freq) / 1000000; - - ir.lirc.rc6_bit = lirctable->rc6_bit; - ir.lirc.flags = lirctable->flags; - ir.lirc.bits = lirctable->bits; - ir.lirc.min_repeat = lirctable->min_repeat; - + ir.cmd = 0; ir.actcmd = 0; ir.lirc.stop = 0; ir.state = LIRC_IDLE; ir.lirc.bit = 0; - ir.lirc.map = map; } } @@ -399,19 +352,19 @@ void LIRC_Send(unsigned long cmd) if(cmd != 0x0000) { ir.lirc.pre_data = ir.lirc.actpre_data; - ir.actcmd = cmd<<(32-ir.lirc.bits); + ir.actcmd = cmd<<(32-lirctable->bits); ir.lirc.post_data = ir.lirc.actpost_data; ir.lirc.stop = 0; ir.lirc.repeats = 0; if(ir.toggle & 0x01) { - togglemask = (unsigned long)(LIRC.table[ir.lirc.map].toggle_bit_mask) << (32-ir.lirc.post_data_bits); + togglemask = (unsigned long)(lirctable->toggle_bit_mask) << (32-lirctable->post_data_bits); ir.lirc.post_data ^= togglemask; - togglemask = (unsigned long)(LIRC.table[ir.lirc.map].toggle_bit_mask>>ir.lirc.post_data_bits) << (32-ir.lirc.bits); + togglemask = (unsigned long)(lirctable->toggle_bit_mask>>lirctable->post_data_bits) << (32-lirctable->bits); ir.actcmd ^= togglemask; - togglemask = (unsigned long)(LIRC.table[ir.lirc.map].toggle_bit_mask>>(ir.lirc.post_data_bits + ir.lirc.bits)) << (32-ir.lirc.pre_data_bits); + togglemask = (unsigned long)(lirctable->toggle_bit_mask>>(lirctable->post_data_bits + lirctable->bits)) << (32-lirctable->pre_data_bits); ir.lirc.pre_data ^= togglemask; } @@ -421,9 +374,9 @@ void LIRC_Send(unsigned long cmd) ir.state++; if(is_RF) { RFasyncmode(true); - cc1100_write1(FREQ2,((LIRC.table[ir.lirc.map].freq)>>16) & 0xFF); - cc1100_write1(FREQ1,((LIRC.table[ir.lirc.map].freq)>>8) & 0xFF); - cc1100_write1(FREQ0,(LIRC.table[ir.lirc.map].freq) & 0xFF); + cc1100_write1(FREQ2,((lirctable->freq)>>16) & 0xFF); + cc1100_write1(FREQ1,((lirctable->freq)>>8) & 0xFF); + cc1100_write1(FREQ0,(lirctable->freq) & 0xFF); cc1100_strobe(STX); } runIR(); @@ -438,7 +391,7 @@ void LIRC_Repeat(void) { void LIRC_Stop(void) { ir.lirc.stop = 1; - if(ir.lirc.bits){ + if(lirctable->bits){ while(ir.state != LIRC_IDLE); } diff --git a/boop/infrared/ir_lirc.h b/boop/infrared/ir_lirc.h index 2154aa9..3541a87 100644 --- a/boop/infrared/ir_lirc.h +++ b/boop/infrared/ir_lirc.h @@ -28,10 +28,10 @@ //#define LIRC_SPACE_FIRST 0x0020 /* bits are encoded as space+pulse */ //#define LIRC_GOLDSTAR 0x0040 /* encoding found on Goldstar remote */ //#define LIRC_GRUNDIG 0x0080 /* encoding found on Grundig remote */ -//#define LIRC_BO 0x0100 /* encoding found on Bang & Olufsen remote */ -#define LIRC_RF 0x0100 /* RF ASK/OOK modulator */ -//#define LIRC_SERIAL 0x0200 /* serial protocol */ -//#define LIRC_XMP 0x0400 /* XMP protocol */ +#define LIRC_BO 0x0100 /* encoding found on Bang & Olufsen remote */ +#define LIRC_RF 0x0200 /* RF ASK/OOK modulator */ +//#define LIRC_SERIAL 0x0400 /* serial protocol */ +//#define LIRC_XMP 0x0800 /* XMP protocol */ /* additinal flags: can be orred together with protocol flag */ //#define REVERSE 0x0800 @@ -40,14 +40,15 @@ #define LIRC_CONST_LENGTH 0x4000 /* signal length+gap is always constant */ #define LIRC_REPEAT_HEADER 0x8000 /* header is also sent before repeat code */ -#define is_rc6 (ir.lirc.flags & LIRC_RC6) -#define is_biphase ((ir.lirc.flags & LIRC_RC5) || is_rc6) -#define is_rcmm (ir.lirc.flags & LIRC_RCMM) -#define is_const (ir.lirc.flags & LIRC_CONST_LENGTH) -#define is_RF (ir.lirc.flags & LIRC_RF) -#define has_header (ir.lirc.phead && ir.lirc.shead) -#define has_foot (ir.lirc.pfoot && ir.lirc.sfoot) -#define has_repeat (ir.lirc.prepeat && ir.lirc.srepeat) +#define is_rc6 (lirctable->flags & LIRC_RC6) +#define is_biphase ((lirctable->flags & LIRC_RC5) || is_rc6) +#define is_rcmm (lirctable->flags & LIRC_RCMM) +#define is_const (lirctable->flags & LIRC_CONST_LENGTH) +#define is_RF (lirctable->flags & LIRC_RF) +#define is_BO (lirctable->flags & LIRC_BO) /* flag for b&o specific protocol MN2017325 */ +#define has_header (lirctable->phead && lirctable->shead) +#define has_foot (lirctable->pfoot && lirctable->sfoot) +#define has_repeat (lirctable->prepeat && lirctable->srepeat) //FS20 Protocol description see http://fhz4linux.info/tiki-index.php?page=FS20%20Protocol #define calcFS20pre(HC1,par1,HC2,par2) ((1<<18) | (HC1<<10) | (par1<<9) | (HC2<<1) | par2) diff --git a/boop/infrared/ir_nrc17.c b/boop/infrared/ir_nrc17.c index afbe81f..229caf4 100644 --- a/boop/infrared/ir_nrc17.c +++ b/boop/infrared/ir_nrc17.c @@ -115,6 +115,7 @@ void __attribute__ ((section(".text.fastcode"))) NRC17_Encode(void) break; } + T1MR0 = cycles * NRC17_Module.lo_border * NRC17_Module.tval; } /* void NRC17_CopyMap(unsigned char xtra, unsigned short *map) diff --git a/boop/infrared/ir_rc5.c b/boop/infrared/ir_rc5.c index 8c6c6c1..624620f 100644 --- a/boop/infrared/ir_rc5.c +++ b/boop/infrared/ir_rc5.c @@ -98,6 +98,7 @@ void __attribute__ ((section(".text.fastcode"))) RC5_Encode (void) } break; } + T1MR0 = cycles * RC5_Module.lo_border * RC5_Module.tval; } void RC5_Init(unsigned char map) diff --git a/boop/infrared/ir_rc6.c b/boop/infrared/ir_rc6.c index d42b43a..990fa08 100644 --- a/boop/infrared/ir_rc6.c +++ b/boop/infrared/ir_rc6.c @@ -148,6 +148,7 @@ void __attribute__ ((section(".text.fastcode"))) RC6_Encode (void) } break; } + T1MR0 = cycles * RC6_Module.lo_border * RC6_Module.tval; } void RC6_Init(unsigned char map) diff --git a/boop/infrared/ir_rca.c b/boop/infrared/ir_rca.c index 84e95d5..1ba24d7 100644 --- a/boop/infrared/ir_rca.c +++ b/boop/infrared/ir_rca.c @@ -120,6 +120,7 @@ void __attribute__ ((section(".text.fastcode"))) RCA_Encode (void) } break; } + T1MR0 = cycles * RCA_Module.lo_border * RCA_Module.tval; } void RCA_LoadMap(unsigned char map) diff --git a/boop/infrared/ir_rcmm.c b/boop/infrared/ir_rcmm.c index 2424391..e477185 100644 --- a/boop/infrared/ir_rcmm.c +++ b/boop/infrared/ir_rcmm.c @@ -117,6 +117,7 @@ void __attribute__ ((section(".text.fastcode"))) RCMM_Encode (void) } + T1MR0 = cycles * RCMM_Module.lo_border * RCMM_Module.tval; } void RCMM_LoadMap(unsigned char map) diff --git a/boop/infrared/ir_rec80.c b/boop/infrared/ir_rec80.c index 6f4f8b1..02fb5f7 100644 --- a/boop/infrared/ir_rec80.c +++ b/boop/infrared/ir_rec80.c @@ -117,6 +117,7 @@ void __attribute__ ((section(".text.fastcode"))) REC80_Encode (void) } break; } + T1MR0 = cycles * REC80_Module.lo_border * REC80_Module.tval; } void REC80_LoadMap(unsigned char map) diff --git a/boop/infrared/ir_recs80.c b/boop/infrared/ir_recs80.c index d15dbd1..cabd96b 100644 --- a/boop/infrared/ir_recs80.c +++ b/boop/infrared/ir_recs80.c @@ -90,6 +90,7 @@ void __attribute__ ((section(".text.fastcode"))) RECS80_Encode (void) } break; } + T1MR0 = cycles * RECS80_Module.lo_border * RECS80_Module.tval; } void RECS80_Init(unsigned char map) diff --git a/boop/infrared/ir_rf.c b/boop/infrared/ir_rf.c index b1dcbe3..8032b17 100644 --- a/boop/infrared/ir_rf.c +++ b/boop/infrared/ir_rf.c @@ -42,7 +42,7 @@ extern volatile unsigned long keyMap[42]; #define IRRF_WAIT 0x01 #define IRRF_BITTIME 40 -#define IRRF_WAITTIME 125 +#define IRRF_WAITTIME 100 void __attribute__ ((section(".text.fastcode"))) IRRF_Encode (void) { @@ -63,6 +63,7 @@ void __attribute__ ((section(".text.fastcode"))) IRRF_Encode (void) } break; } + T1MR0 = 15*1000; } void IRRF_Init(unsigned char map) @@ -100,9 +101,10 @@ void IRRF_Repeat(void) struct RFendpoint_* cur_ep; cur_ep = (struct RFendpoint_*)ir.general.trail; if((cur_ep) && !(cur_ep->flags & EPnewdata)) { - cur_ep->dest = (ir.actcmd & 0xff00) >> 8; - cur_ep->data[0] = (ir.actcmd & 0x00ff); - cur_ep->bufferlen = 1; + cur_ep->dest = 0; + cur_ep->data[1] = (ir.actcmd & 0x00ff); + cur_ep->data[0] = (ir.actcmd & 0xff00) >> 8; + cur_ep->bufferlen = 2; cur_ep->flags |= EPenabled | EPoutput | EPnewdata; RF_changestate(RFtx); diff --git a/boop/infrared/ir_sirc.c b/boop/infrared/ir_sirc.c index 0bcfa8a..dd9e4b4 100644 --- a/boop/infrared/ir_sirc.c +++ b/boop/infrared/ir_sirc.c @@ -103,6 +103,8 @@ void __attribute__ ((section(".text.fastcode"))) SIRC_Encode (void) break; } + + T1MR0 = cycles * SIRC_Module.lo_border * SIRC_Module.tval; } void SIRC_Init(unsigned char map) diff --git a/boop/infrared/ir_spaceenc.c b/boop/infrared/ir_spaceenc.c index d6c0ccc..73b0228 100644 --- a/boop/infrared/ir_spaceenc.c +++ b/boop/infrared/ir_spaceenc.c @@ -137,6 +137,7 @@ void __attribute__ ((section(".text.fastcode"))) SPACEENC_Encode (void) } break; } + T1MR0 = cycles * SPACEENC_Module.lo_border * SPACEENC_Module.tval; } void SPACEENC_LoadMap(unsigned char map) diff --git a/boop/infrared/pwm.c b/boop/infrared/pwm.c new file mode 100644 index 0000000..7c891c6 --- /dev/null +++ b/boop/infrared/pwm.c @@ -0,0 +1,82 @@ +/* + pwm.c - pwm control + Copyright (C) 2017 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "global.h" +#include "lpc2220.h" +#include "irq.h" + +void PWM_init(void) +{ + //Set pin P0.21 IR_OUT as PWM + PINSEL1 &= ~(3 << (10)); // IO + PINSEL1 |= (1 << (10)); // PWM5 + + PWMTC = 0; //Timer Counter + PWMPR = 0; //Prescale Register + PWMPC = 0; //Prescale Counter + + PWMMR0 = 416; // pwm rate + PWMMR2 = 0x00; // pwm value sound + PWMMR5 = 0x00; // pwm value IR + + PWMLER = 0x26; //Latch Enable + PWMMCR = 0x03; //Match Control + PWMPCR |= (1<<13) | (1<<10); + PWMTCR = 0x03; + PWMTCR = 0x09; + + /* PWMTC = 0; + PWMPR = 7; + PWMMR0 = 0x1E6; // pwm rate + PWMMR2 = 0x00; // pwm value + PWMLER = 0x05; + PWMPCR = (1<<10); +*/ + + //VICVectAddr0 = (unsigned long)&(soundIRQ); + //VICVectCntl0 = VIC_SLOT_EN | INT_SRC_PWM; + VICIntSelect |= INT_PWM; + VICIntEnable = INT_PWM; + +} + +void PWM_set_frequency(unsigned long f) +{ + if(f<5000) { + PWMPR = 7; + PWMMR0 = 1875000 / f; + } else { + PWMPR = 0; + PWMMR0 = 15000000 / f; + } + PWMLER |= 0x01; //Latch Enable + + + if(f < 32000) { + PWMMCR = 0x03; + } else { + PWMMCR = 0x02; + } + +} + +void PWM_set_IR_duty_cycle(unsigned char d) { + PWMMR5 = (PWMMR0 * d) / 100; + PWMLER |= 0x20; +} + diff --git a/boop/infrared/pwm.h b/boop/infrared/pwm.h new file mode 100644 index 0000000..8d47ff6 --- /dev/null +++ b/boop/infrared/pwm.h @@ -0,0 +1,26 @@ +/* + pwm.h - pwm control + Copyright (C) 2017 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + + +void PWM_init(void); +void PWM_set_frequency(unsigned long f); +void PWM_set_IR_duty_cycle(unsigned char d); + + diff --git a/boop/interrupt/irq.c b/boop/interrupt/irq.c index 9c8f965..331fa55 100644 --- a/boop/interrupt/irq.c +++ b/boop/interrupt/irq.c @@ -71,12 +71,12 @@ unsigned restoreIRQ(unsigned oldCPSR) // (where's the vector? in lpc2220_rom.ld ?) void __attribute__ ((section(".text.fastcode"))) FIQ_Routine (void) { - while ((PWMIR == 0x01) || (T1IR == 1)) + //while ((PWMIR == 0x01)) { if (PWMIR == 0x01) soundIRQ(); // sound, backlight - if (T1IR == 1) - irIRQ(); // IR + //if (T1IR == 1) + // irIRQ(); // IR } } diff --git a/boop/main.c b/boop/main.c index 5f8fba8..9744389 100644 --- a/boop/main.c +++ b/boop/main.c @@ -31,6 +31,7 @@ //#include "sounds.h" //#include "sound3.h" #include "infrared.h" +#include "pwm.h" #include "codes.h" #include "encoders.h" #include "ir_selector.h" @@ -87,8 +88,8 @@ void setSpeed(unsigned char sp) VPBDIV = 0x00; - BCFG0 = 0x100004A0; - BCFG2 = 0x100004A0; + BCFG0 = 0x10001CA0; + BCFG2 = 0x10001CA0; BCFG1 = 0x00000C21; sysInfo |= SYS_TURBO; break; @@ -102,8 +103,8 @@ void setSpeed(unsigned char sp) VPBDIV = 0x02; - BCFG0 = 0x10000420; - BCFG2 = 0x10000420; + BCFG0 = 0x10000A20; + BCFG2 = 0x10000A20; BCFG1 = 0x00000400; sysInfo &= ~SYS_TURBO; break; @@ -198,6 +199,8 @@ void cpu_idle () if(U0SCR) return; + return; + /* only idle mode instead of power down when: * * backlight on * * IR transmission @@ -240,7 +243,8 @@ int main(void) FIOSET0 |= (1<<12); FIOCLR0 |= (1<<4); - setSpeed(SPEED_30); + setSpeed(SPEED_60); + BFS_Mount(); // flash file system lcd_init(0); serial_init(); @@ -251,11 +255,13 @@ int main(void) initKeys(); initSound(); - startSoundIRQ(); + //startSoundIRQ(); initIR(); startIrIRQ(); + PWM_init(); + RF_init(); load_RF_setting(); startRFIRQ(); @@ -279,10 +285,8 @@ int main(void) set_font(BOLDFONT); - BFS_Mount(); // flash file system - load_RC_setting(); // learned remote codes load_setting(); // display settings - + load_RC_setting(); // learned remote codes // recorded raw IR commands { diff --git a/boop/timer/timerfuncs.c b/boop/timer/timerfuncs.c index f7749c1..7467050 100644 --- a/boop/timer/timerfuncs.c +++ b/boop/timer/timerfuncs.c @@ -42,7 +42,7 @@ void startTimerIRQ(void) T0TCR = 0x02; // reset timer T0TC = 1870; T0PR = 0x0e; // 15.000.000 Hz / 15 = 1.000.000 Hz --> PR = 15 - 1 = 0x0e - T0MR0 = 5000; // 1.000.000 Hz / 5000 = 200 Hz = 5 msec intervall time + T0MR0 = 250; // 1.000.000 Hz / 250 = 4000 Hz = 0,25msec intervall time T0MCR = 0x03; // reset and issue IRQ on TC == MR0 T0TCR = 0x01; // enable timer diff --git a/boop/timer/timerirq.c b/boop/timer/timerirq.c index a19cfae..873274f 100644 --- a/boop/timer/timerirq.c +++ b/boop/timer/timerirq.c @@ -21,14 +21,37 @@ #include "timerfuncs.h" #include "lcd.h" +#define TIMER_PRESCALER 20 + struct CB callbacks[MAX_CB]; unsigned long* timeouts[MAX_TO]; +unsigned char timerPrescaler = TIMER_PRESCALER; +unsigned char bl_val, cmp_val; // backlight PWM - -// wird alle 5 ms aufgerufen (s. startTimerIRQ() in timerfuncs) +// wird alle 0.25 ms aufgerufen (s. startTimerIRQ() in timerfuncs) // bearbeitet eingetragene "timer" void __attribute__ ((section(".text.fastcode"))) timerIRQ(void) { + // backlight pwm + cmp_val += bl_val; + if (cmp_val >= 63) + { + FIODIR0 |= (1<<4); // sck0/P0.4 + cmp_val -= 63; + } + else + { + FIODIR0 &= ~(1<<4); // sck0/P0.4 + } + + + if(--timerPrescaler) { + T0IR = 1; + return; + } + timerPrescaler = TIMER_PRESCALER; + + //5 msec intervall time unsigned int cnt; struct CB *cur_cb;