Difference between revisions of "Marantz SR5600"

From LinuxMCE
Jump to: navigation, search
m (Added category: GSD)
 
(21 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 +
[[Category: Hardware]]
 +
[[Category:Amps_Receivers]]
 +
{{versioninfo}}
 
{| align="right"
 
{| align="right"
 
   | __TOC__
 
   | __TOC__
 
   |}
 
   |}
  
[[Category: Hardware]]
 
 
[[Category: Audio]]
 
[[Category: Audio]]
 +
[[Category:Tutorials]]
 +
[[Category: GSD]]
  
 
More info about [http://us.marantz.com/689.asp?category=AV&model=SR5600&go.x=14&go.y=8 device ] :
 
More info about [http://us.marantz.com/689.asp?category=AV&model=SR5600&go.x=14&go.y=8 device ] :
Line 13: Line 17:
  
 
First I've closely examined existing templates for Yamaha receiver, RS232 Plasma and tried to learn things. Since there is currently no special screen prepared for control of Audio/Tuner receiver device, I decided to use 'TV - LiveTV' device with template #1751, that already has associated media screen for tuner control (it's meant for TV tuner control, but is close enough for a start)...
 
First I've closely examined existing templates for Yamaha receiver, RS232 Plasma and tried to learn things. Since there is currently no special screen prepared for control of Audio/Tuner receiver device, I decided to use 'TV - LiveTV' device with template #1751, that already has associated media screen for tuner control (it's meant for TV tuner control, but is close enough for a start)...
 +
 +
I have also decided to use Marantz in Multiroom configuration (7+1 output is in this case split to 4+1 output ("Zone Main") and 2ch stereo output ("Zone Multiroom"). There is also third zone - "Line Out", but this is only preamp output of Multiroom Zone, but can have separate volume/mute control. Template has currently basic support for all 3 zones. There are still few things to be added, but I'm learning Ruby slowly and have few problems, so maybe I will get some help from more experienced guys...
 +
 +
The whole idea of implementation is to have 3 separate zones (each represented by "Zone" child devices (extended template #1867), to whom you can connect your audio sources by audio pipes. Currently squeezebox devices and other HW players will work ok, there are some slight problems with ordinary Xine player on Onscreen Orbiter, cause whole Orbiter is connected on pipe and when the media stops playing, On command for Orbiter instead of Off for player is propagated through pipe, so your amplifier stays On for some time even after stop...
 +
 
   
 
   
''LinuxMCE Dan: Can you please add new media screen for such type of devices (http://plutohome.com/support/mantis/view.php?id=3151)
+
''LinuxMCE Developers: Can you please add new media screen for such type of devices (http://plutohome.com/support/mantis/view.php?id=3151)
 
and maybe even document procedure on Wiki.  
 
and maybe even document procedure on Wiki.  
 
It would ease similar contributions from other users...''
 
It would ease similar contributions from other users...''
 
    
 
    
== Adding new template ==
+
== Description of needed templates ==
=== Specify device data and parameters ===
+
 
  Description : SR5600
+
I hope that this template will be available with stock LMCE distribution, so you won't have to create that template from scratch. Template is called "SR Series MultiRoom RS232" to be different from existing template for Marantz in 7+1 configuration ("SR Series RS232"). The main difference between those templates is that this template is more complicated, cause it gives you independent controls of more zones and therefore it has a bit different logic (for example main general power is switched off only when all zones are muted, zones are switched on/off only by muting them)
 +
 
 +
For template to be functional I've made certain extensions to existing template for "Zone" that I hope will be usefull also to others...
 +
 
 +
=== Important device data and parameters for "SR Series MultiRoom RS232" template ===
 +
  Description : SR Series MultiRoom RS232
 
  Implements DCE : yes
 
  Implements DCE : yes
 
  Command line : Generic_Serial_Device
 
  Command line : Generic_Serial_Device
Line 30: Line 44:
 
  Device data
 
  Device data
 
  Current Data                                     Comments                                 Default Value
 
  Current Data                                     Comments                                 Default Value
  #37 COM Port on PC(string)                     The serial port
+
  #37 COM Port on PC                                                                             /dev/ttyS0
  #76 COM Port ParityBit/Stop(string)             Parity/Stop bits (factory defaults) 8N1
+
  #76 COM Port ParityBit/Stop                                                                 N81
  #78 COM Port BaudRate(string)                       Baud rate (factory default)         B9600
+
  #78 COM Port BaudRate                                                                         B9600
  #157 Discrete Volume(bool)                     Indicates if the volume on...              1  
+
#220 Process Child Commands In Pare                                                              1 (needed to have ability to send all commands to parent)
 +
  #157 Discrete Volume(bool)                                                                 1
 +
#220 Process Child Commands In Pare(bool)
  
 
Settings are factory defaults and should't be changed (9600 baud rate, 8 bits, 1 stop bit)...
 
Settings are factory defaults and should't be changed (9600 baud rate, 8 bits, 1 stop bit)...
  
 
=== 'Edit Ruby code' (on template page)  ===
 
=== 'Edit Ruby code' (on template page)  ===
 +
==== 'Determining proper set of inputs' ====
  
==== 'Add/remove commands' ====
+
I've added all inputs that are present on device. There is also a special input called "FM" where I connected Live TV embedded device to be able to control tuner functions (tuning/searching up/down, go to preset stations, etc...)
First, I clicked on 'Add/remove commands' and clicked on commands that are supported by device...
+
  
I had to add a lot of new command groups, cause they were non existent. In this way one can reuse those command groups also for other devices. I've created following command groups :
 
  
MultiRoom Inputs
 
MultiRoom Line Standard Commands
 
MultiRoom Line Volume Commands
 
MultiRoom Standard Commands
 
MultiRoom Volume Commands
 
Tone Control
 
  
I also added few commands to already existing command groups (like Inputs,...). I just hope that those change will get into main LMCE database, so everyone will be able to reuse it.
+
==== 'Set proper set of commands' ====
 +
 
 +
Basically I've added command groups :
 +
Ruby Internal Commands
 +
Standard Receiver Command
 +
Volume Commands
 +
and added some needed commands (important is command to tune to certain FM frequency, so you can later add scenarios for tuning to certain FM stations....)
 +
 
  
 
==== 'Add Ruby snippets to commands'====  
 
==== 'Add Ruby snippets to commands'====  
Edited coresponding Ruby snippets for each command. Basically those are just simple strings that get send on rs232 to take proper action on device according to received command from LinuxMCE...
 
  
 +
I've created new IR/Codeset group called "Marantz SR Multiroom RS232", although I'm not sure how to handle it. Have also edited coresponding Ruby snippets for each command. Basically those are just simple strings that get send on rs232 to take proper action on device according to received command from LinuxMCE... There are also a lot of other functions that help :
 +
- determining for which child zone command is targeted
 +
- to "normalize" volume levels between Marantz's internal dB units and range of 0-100
  
Power
+
 
 +
Simpler commands from Ruby part of template :
 +
<pre><nowiki>
 +
 
 +
  Power
 
  #193 Off
 
  #193 Off
        <$"@PWR:1\r"$>
+
#SendMultiZoneCommand(cmd, ["@PWR:1", "@MSP:1", "@MAM:2"]) SendMultiZonePowerOffCommand(cmd, ["@AMT:2", "@MSP:1", "@MAM:2"])
 +
 
  #192 On
 
  #192 On
        <$"@PWR:2\r"$> sleep(1) <$"@AMT:1\r"$> @mute = false <$"@VOL:0-40\r"$> # main volume <$"@MSV:0-40\r"$> # multi speaker volume
+
#SendMultiZoneCommand(cmd, ["@PWR:2", "@MSP:2", "@MAM:1"]) SendMultiZonePowerOnCommand(cmd, ["@AMT:1", "@MSP:2", "@MAM:1"])
 +
 
  #194 Toggle Power
 
  #194 Toggle Power
        <$"@PWR:0\r"$>
+
 
+
Inputs
+
Inputs
 +
#169 AM
 +
SendMultiZoneCommand(cmd, ["@SRC:H", "@MSC:H", "@MSC:H"])
 +
 +
#164 Aux
 +
SendMultiZoneCommand(cmd, ["@SRC:9", "@MSC:9", "@MSC:9"])
 +
 +
#172 Aux 2
 +
SendMultiZoneCommand(cmd, ["@SRC:A", "@MSC:A", "@MSC:A"])
 +
 
  #162 CD
 
  #162 CD
        <$"@SRC:C\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:C", "@MSC:C", "@MSC:C"])
 +
 
  #420 CDR
 
  #420 CDR
        <$"@SRC:D\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:D", "@MSC:D", "@MSC:D"])
 +
 
  #178 DSS
 
  #178 DSS
        <$"@SRC:4\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:4", "@MSC:4", "@MSC:4"])
 +
 
  #165 DVD
 
  #165 DVD
        <$"@SRC:2\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:2", "@MSC:2", "@MSC:2"])
#943 MultiRoom CD
+
   
        <$"@MSC:C\r"$>
+
  #170 FM
#945 MultiRoom CDR
+
SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"])
        <$"@MSC:D\r"$>
+
   
  #942 MultiRoom DSS
+
        <$"@MSC:4\r"$>
+
  #940 MultiRoom DVD
+
        <$"@MSC:2\r"$>
+
#944 MultiRoom Tape
+
        <$"@MSC:E\r"$>
+
#946 MultiRoom Tuner
+
        <$"@MSRC:F\r"$>
+
#939 MultiRoom TV
+
        <$"@MSC:1\r"$>
+
  #941 MultiRoom VCR-1
+
        <$"@MSC:3\r"$>
+
 
  #160 Tape / Tape 1
 
  #160 Tape / Tape 1
        <$"@SRC:E\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:E", "@MSC:E", "@MSC:E"])
 +
 
  #166 Tuner
 
  #166 Tuner
        <$"@SRC:F\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:F", "@MSC:F", "@MSC:F"])
 +
 
  #161 TV
 
  #161 TV
        <$"@SRC:1\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:1", "@MSC:1", "@MSC:1"])
 +
 
  #282 VCR-1
 
  #282 VCR-1
        <$"@SRC:3\r"$>
+
SendMultiZoneCommand(cmd, ["@SRC:3", "@MSC:3", "@MSC:3"])
 +
 +
DSP Modes (Audio)
 +
#891 All Ch Stereo
 +
#<$"@SUR:0H\r"$> SendIrCommand("@SUR:0H")
 +
 +
 +
#97 Mute
 +
SendMultiZoneCommand(cmd, ["@AMT:0", "@MSM:0", "@MAM:0"])
 +
 +
 +
#90 Vol Down
 +
SendMultiZoneCommand(cmd, ["@VOL:2", "@MSV:2", "@MVL:2"])
 +
 +
#89 Vol Up
 +
SendMultiZoneCommand(cmd, ["@VOL:1", "@MSV:1", "@MVL:1"])
 +
 +
Speed Ctrl
 +
#125 Scan Back/Rewind
 +
</nowiki></pre>
 +
 
 +
 
 +
More important parts with more Ruby code :
 +
 
 +
<pre><nowiki>
 +
###########################################################3 Internal Methods
 +
# To do list :
 +
# - parsing of input messages (inputs,mute,volume,power)
 +
# - handling of tuner (with live/TV child device)
 +
# - to properly send events and set device current volume data
 +
 
 +
def DecodeReceivedInfo_candidate(response)
 +
# Examples: Mute/On/Off: @AMT:1,@MSP:2,@MAM:2,  Volume: @VOL:-25,@MSV:-56,@MVL:-56  Inputs:@MSC:2E,@SRC:22,@SRC:2E
 +
  log("DecodeReceivedInfo1: " + response + "\n");
 +
  avrcommand = response[1..3]
 +
  avrvalue = response[5]
 +
  log("DecodeReceivedInfo2: " + response + " -> Command:"+ avrcommand.to_s + " Value: " + avrvalue.to_s + "\n");
 +
 
 +
  case avrcommand
 +
# Input Source changed
 +
    when 'SRC'
 +
    log("Main Zone Input Changed to "+ avrvalue.to_s+ "\n");
 +
    input_param=0
 +
   
 +
    case avrvalue
 +
    when '1'
 +
    log('Main Zone Input Changed to #161: TV')
 +
    input_param=161
 +
    temp_state="Input: TV"
 +
    when '2'
 +
    log('Main Zone Input Changed to #165: DVD')
 +
    input_param=165
 +
    temp_state="Input: TV"
 +
    when '3'
 +
    log('Main Zone Input Changed to #282: VCR-1')
 +
    input_param=282
 +
    temp_state="Input: TV"
 +
    when '4'
 +
    log('Main Zone Input Changed to #178: DSS')
 +
    input_param=178
 +
    temp_state="Input: TV"
 +
    when '9'
 +
    log('Main Zone Input Changed to #164: AUX')
 +
    input_param=164
 +
    temp_state="Input: TV"
 +
    when 'A'
 +
    log('Main Zone Input Changed to #171: AUX2')
 +
    input_param=171
 +
    temp_state="Input: TV"
 +
    when 'C'
 +
    log('Main Zone Input Changed to #162: CD')
 +
    input_param=162
 +
    temp_state="Input: TV"
 +
    when 'D'
 +
    log('Main Zone Input Changed to #420: CDR')
 +
    input_param=420
 +
    temp_state="Input: TV"
 +
    when 'E'
 +
    log('Main Zone Input Changed to #160: TAPE')
 +
    input_param=160
 +
    temp_state="Input: TV"
 +
    when 'F'
 +
    log('Main Zone Input Changed to #166: TUNER')
 +
    input_param=166
 +
    temp_state="Input: TV"
 +
    when 'G'
 +
    log('Main Zone Input Changed to #170: FM')
 +
    input_param=160
 +
    temp_state="Input: TV"
 +
    when 'H'
 +
    log('Main Zone Input Changed to #169: AM')
 +
    input_param=169
 +
    temp_state="Input: TV"
 +
    end
 +
#    device_id = device_.mapPortChannel_Device_.[0.to_s]
 +
log("======= Determiming device ID for Zone 0 : " + device_id.to_s + "\n")
 +
device_.mapPortChannel_Device_.each do |key, value|
 +
log(key.to_s + " => " + value.to_s+ "\n")
 +
end
 +
    cmd = Command.new(device_id, -1001, 1, 2, 49);
 +
    cmd.params_[41] = input_param.to_s();
 +
    SendCommand(cmd);
 +
    SetDeviceDataInDB( device_id, 200, temp_state ) # 200 = DEVICEDATA_State_CONST
 +
 
 +
    when 'VOL'
 +
    volume = response[5..-1].to_i();
 +
    volume_norm = NormalizeVolume_MainZone(volume)
 +
    log("Main Zone Volume Changed: " + volume.to_s + " Normalized Value: " + volume_norm.to_s + "\n");
 +
#    device_id = device_.mapPortChannel_Device_.[0.to_s]
 +
log("======= Determiming device ID for Zone 0 : " + device_id.to_s + "\n")
 +
device_.mapPortChannel_Device_.each do |key, value|
 +
log(key.to_s + " => " + value.to_s+ "\n")
 +
end
 +
    SetDeviceDataInDB( device_id, 158, volume_norm ) # 158 = DEVICEDATA_Volume_Level_CONST
 +
    cmd = Command.new(device_id, -1001, 1, 2, 71);
 +
    cmd.params_[30] = volume_norm
 +
    SendCommand(cmd);
 +
    when 'PWR'
 +
    case avrvalue
 +
    when '1'
 +
    log("Device Power Changed: OFF");
 +
    cmd.params_[10] = "0";
 +
    $DevicePower = 0
 +
    when '2'
 +
    log("Device Power Changed: ON");
 +
    cmd.params_[10] = "1";
 +
    $DevicePower = 1
 +
    end
 +
    cmd = Command.new(device_.devid_, -1001, 1, 2, 48);
 +
    SendCommand(cmd);
 +
    else
 +
    log("Yet not implemented: Handler for command: " + avrcommand.to_s)
 +
    end
 +
   
 +
end   
 +
 
 +
 
 +
def DecodeReceivedInfo(response)
 +
# Examples: Mute/On/Off: @AMT:1,@MSP:2,@MAM:2,  Volume: @VOL:-25,@MSV:-56,@MVL:-56  Inputs:@MSC:2E,@SRC:22,@SRC:2E
 +
  log("DecodeReceivedInfo1: " + response + "\n");
 +
  avrcommand = response[1..3]
 +
  avrvalue = response[5]
 +
  log("DecodeReceivedInfo2: " + response + " -> Command:"+ avrcommand.to_s + " Value: " + avrvalue.to_s + "\n");
 +
 
 +
  case avrcommand
 +
    when 'VOL'
 +
    volume = response[5..-1].to_i();
 +
    volume_norm = NormalizeVolume_MainZone(volume)
 +
    log("Main Zone Volume Changed: " + volume.to_s + " Normalized Value: " + volume_norm.to_s + "\n");
 +
#    device_id = device_.mapPortChannel_Device_.[0.to_s]
 +
log("======= Determiming device ID for Zone 0 : " + device_id.to_s + "\n")
 +
device_.mapPortChannel_Device_.each do |key, value|
 +
log(key.to_s + " => " + value.to_s+ "\n")
 +
if (key.to_s == "0")
 +
device_id = value
 +
end
 +
end
 +
    SetDeviceDataInDB( device_id, 158, volume_norm ) # 158 = DEVICEDATA_Volume_Level_CONST
 +
    cmd = Command.new(device_id, -1001, 1, 2, 71);
 +
    cmd.params_[30] = volume_norm
 +
    SendCommand(cmd);
 +
    when 'PWR'
 +
    case avrvalue
 +
    when '1'
 +
    log("Device Power Changed: OFF")
 +
    cmd.params_[10] = "0";
 +
    $DevicePower = 0
 +
    when '2'
 +
    log("Device Power Changed: ON");
 +
    cmd.params_[10] = "1";
 +
    $DevicePower = 1
 +
    end
 +
    cmd = Command.new(device_.devid_, -1001, 1, 2, 48);
 +
    SendCommand(cmd);
 +
    else
 +
    log("Yet not implemented: Handler for command: " + avrcommand.to_s)
 +
    end
 +
   
 +
end   
 +
 
 +
 
 +
def ReceiveReportCommand()
 +
@buff = conn_.RecvDelimited("\r", 1000)
 +
log("Cmd response from Marantz: " + @buff + "\n")
 +
log("Calling DecodeReceivedInfo: " + @buff + "\n")
 +
temp_resp=@buff;
 +
DecodeReceivedInfo(temp_resp)
 +
log("End of DecodeReceivedInfo: " + temp_resp + "\n")
 +
end
 +
 
 +
def SendIrCommand(command)
 +
        log("SendIrCommand: " + command + "\n")
 +
conn_.Send(command+ "\r")
 +
        log("Sending Command: " + command + "\n")
 +
ReceiveReportCommand()
 +
end
 +
 
 +
def log(line)
 +
#          $log = File.open("/var/log/pluto/" + device_.devid_.to_s + "_Generic_Serial_Device.log", "a")
 +
  $log = File.open("/var/log/pluto/Marantz_SR5600.log", "a")
 +
  logTime = Time.now
 +
  timeStr = logTime.strftime("%d-%m-%Y  %H:%M:%S  ")
 +
 
 +
  $log.puts timeStr + "(***):" + line.to_s
 +
          $log.close
 +
end
 +
 
 +
def SendMultiZoneCommand(cmd, commandsArray, commandParam="")
 +
        log("Got Command with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
 +
zone = GetZone(cmd.devidto_)
 +
if( zone >= 0 and zone < commandsArray.size )
 +
        zone_desc=device_.childdevices_[cmd.devidto_].devdata_[186]
 +
log("Determine zone for command : " + zone_desc + "[" + zone.to_s + "]\n")
 +
SendIrCommand(commandsArray[zone] + commandParam.to_s)
 +
else
 +
log("SendMultiZoneCommand: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
 +
end
 +
end
 +
 
 +
 
 +
def SendMultiZonePowerOnCommand(cmd, commandsArray, commandParam="")
 +
#It will Unmute Zone first and then see also global power should be turned on...
 +
        log("Got Power On Command with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
 +
zone = GetZone(cmd.devidto_)
 +
if( zone >= 0 and zone < commandsArray.size )
 +
        zone_desc=device_.childdevices_[cmd.devidto_].devdata_[186]
 +
log("Determine zone for command : " + zone_desc + "[" + zone.to_s + "]\n")
 +
SendIrCommand(commandsArray[zone] + commandParam.to_s)
 +
$ZoneStatus[zone.to_s] = 'ON'
 +
log("*** Setting zone : " + zone_desc + "[" + zone.to_s + "] to ON\n")
 +
ShowZones()
 +
if ($DevicePower == 0)
 +
SendIrCommand("@PWR:2")
 +
end
 +
$DevicePower = 1
 +
elsif (zone == -1)
 +
if ($DevicePower == 0)
 +
SendIrCommand("@PWR:2")
 +
end
 +
$DevicePower = 1
 +
log("####### Powering device On\n")
 +
else
 +
log("SendMultiZonePowerOnCommand: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
 +
end
 +
end
 +
 
 +
def SendMultiZonePowerOffCommand(cmd, commandsArray, commandParam="")
 +
#It will Mute Zone first and then see if also global power can be turned off...
 +
        log("Got Power Off Command with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
 +
zone = GetZone(cmd.devidto_)
 +
if( zone >= 0 and zone < commandsArray.size )
 +
        zone_desc=device_.childdevices_[cmd.devidto_].devdata_[186]
 +
log("Determine zone for command : " + zone_desc + "[" + zone.to_s + "]\n")
 +
SendIrCommand(commandsArray[zone] + commandParam.to_s)
 +
$ZoneStatus[zone.to_s] = 'OFF'
 +
log("*** Setting zone : " + zone_desc + "[" + zone.to_s + "] to OFF\n")
 +
ShowZones()
 +
if (($ZoneStatus["0"] == 'OFF') and ($ZoneStatus["1"] == 'OFF') and ($ZoneStatus["2"] == 'OFF'))
 +
SendIrCommand("@PWR:1")
 +
$DevicePower = 0
 +
log("####### All zones are muted - device is powered Off\n")
 +
end
 +
else
 +
log("SendMultiZonePowerOffCommand: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
 +
end
 +
end
 +
 
 +
 
 +
def GetZone(deviceDestination)
 +
if( device_.mapDevice_PortChannel_.has_key?(deviceDestination) and
 +
device_.mapDevice_PortChannel_[deviceDestination] != nil and
 +
!device_.mapDevice_PortChannel_[deviceDestination].empty? )
 +
return device_.mapDevice_PortChannel_[deviceDestination].to_i
 +
end
 +
 +
return -1
 +
end
 +
 
 +
def ShowZonesDebug()
 +
log("####### Dev 2 PortChanel\n")
 +
device_.mapDevice_PortChannel_.each do |key, value|
 +
log(key.to_s + " => " + value.to_s + "\n")
 +
end
 +
 +
log("======= PortChanel 2 Dev\n")
 +
device_.mapPortChannel_Device_.each do |key, value|
 +
log(key.to_s + " => " + value.to_s+ "\n")
 +
end
 +
end
 +
 
 +
 
 +
 
 +
def ShowZonesInitialVolumes()
 +
log("####### Show Initial Volume Levels for zones\n")
 +
device_.mapDevice_PortChannel_.each do |key, value|
 +
        volume = device_.childdevices_[key].devdata_[208]
 +
log("Zone " + value.to_s + " => " + volume.to_s + "\n")
 +
SetVolumeInZone(volume,value)
 +
end
 +
 +
end
 +
 
 +
 
 +
def ShowZones()
 +
temp = "####### Zones Status : "
 +
device_.mapDevice_PortChannel_.each do |key, value|
 +
temp = temp + " | Zone " + value.to_s + " => " + $ZoneStatus[value]
 +
end
 +
temp = temp + "\n"
 +
log(temp)
 +
end
 +
 
 +
 
 +
def SetZones(state)
 +
log("####### Setting all zones to " + state + "\n")
 +
device_.mapDevice_PortChannel_.each do |key, value|
 +
$ZoneStatus[value] = state
 +
log("Zone " + value.to_s + " => " + state + "\n")
 +
end
 +
end
 +
 
 +
def InitZones()
 +
log("####### Initializing all zones to OFF\n")
 +
device_.mapDevice_PortChannel_.each do |key, value|
 +
$ZoneStatus[value] = 'OFF'
 +
log("Zone " + value.to_s + " => " + $ZoneStatus[value] + "\n")
 +
end
 +
log("####### Print $ZoneStatus Hash:\n")
 +
$ZoneStatus.each do |key, value|
 +
log("Zone " + key.to_s + " => " + value.to_s + "\n")
 +
end
 +
end
 +
 
 +
def SetVolumeInZone(level,zone)
 +
# Sets Normalized Volume Level (0..100) in certain zone
 +
log("SetVolumeInZone: volume: " + level.to_s + " => Zone: " + zone + "\n")
 +
 
 +
if ( zone == "0")
 +
log("SetVolumeInZone0: volume: " + level.to_s + " => Zone: " + zone + "\n")
 +
      new_level = DeNormalizeVolume_MainZone(level.to_i)
 +
log("SetVolumeInZone00: volume: " + level.to_s + " => Zone: " + zone + "\n")
 +
      temp_str="@VOL:0"+new_level.to_s;
 +
      log("SetVolumeInZone: About to send command :" + temp_str + "\n")
 +
      SendIrCommand(temp_str)
 +
elsif ( zone == "1")
 +
log("SetVolumeInZone1: volume: " + level.to_s + " => Zone: " + zone + "\n")
 +
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
 +
log("SetVolumeInZone11: volume: " + level.to_s + " => Zone: " + zone + "\n")
 +
      temp_str="@MSV:0"+new_level.to_s;
 +
      log("SetVolumeInZone: About to send command :" + temp_str + "\n")
 +
      SendIrCommand(temp_str)
 +
elsif ( zone == "2")
 +
log("SetVolumeInZone2: volume: " + level.to_s + " => Zone: " + zone + "\n")
 +
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
 +
# log("SetVolumeInZone22: volume: " + level + " => Zone: " + zone + "\n")
 +
      temp_str="@MVL:0"+new_level.to_s;
 +
      log("SetVolumeInZone: About to send command :" + temp_str + "\n")
 +
      SendIrCommand(temp_str)
 +
else
 +
      log("SetVolumeInZone: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
 +
end
 +
log("SetVolumeInZone End: volume: " + level.to_s + " => Zone: " + zone + "\n")
 +
 
 +
end
 +
 
 +
 
 +
def NormalizeVolume_MainZone(level)
 +
# Normalizes Marantz Volume Level (-99..+10) to 0-100 boundaries for Main Zone
 +
temp = (level+100)/110.0*100.0
 +
temp=temp.round
 +
        log("Normalizing Main Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
 +
return temp
 +
end
 +
 
 +
def NormalizeVolume_OtherZone(level)
 +
# Normalizes Marantz Volume Level to 0-100 boundaries for Second Zone (-90..0)
 +
temp = ((level+90.0)/90.0)*100.0
 +
temp=temp.round
 +
        log("Normalizing Other Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
 +
return temp
 +
end
 +
 
 +
def DeNormalizeVolume_MainZone(level)
 +
# DeNormalizes volume level in 0-100 boundaries to Marantz Volume Level (-99..+10) for Main Zone
 +
temp = (level/100.0)*110.0-99
 +
temp=temp.round
 +
        log("DeNormalizing Main Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
 +
return temp
 +
end
 +
 
 +
def DeNormalizeVolume_OtherZone(level)
 +
# DeNormalizes volume level in 0-100 boundaries to Marantz Volume Level (-90..0) for Other Zone
 +
temp = ((level/100.0)*90.0)-90.0
 +
temp=temp.round
 +
        log("DeNormalizing Other Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
 +
return temp
 +
end
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
###########################################################Process Incoming Data
 +
@buff = conn_.RecvDelimited("\r", 1000)
 +
log("Info from Marantz: " + @buff + "\n")
 +
temp_line=@buff
 +
log("1Calling DecodeReceivedInfo: " + temp_line + "\n")
 +
DecodeReceivedInfo(temp_line)
 +
log("1End of DecodeReceivedInfo: " + temp_line+ "\n")
 +
 
 +
 
 +
 
 +
############################################################384 Process Receive Command For Child
 +
log("Received command for child with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
 +
case cmd.id_
 +
    when 169         
 +
#      cmd_169(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:H", "@MSC:H", "@MSC:H"])
 +
    when 164         
 +
#      cmd_164(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:9", "@MSC:9", "@MSC:9"])
 +
    when 172         
 +
#      cmd_172(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:A", "@MSC:A", "@MSC:A"])
 +
    when 162         
 +
#      cmd_162(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:C", "@MSC:C", "@MSC:C"])
 +
    when 420         
 +
#      cmd_420(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:D", "@MSC:D", "@MSC:D"])
 +
    when 178         
 +
#      cmd_178(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:4", "@MSC:4", "@MSC:4"])
 +
    when 165         
 +
#      cmd_165(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:2", "@MSC:2", "@MSC:2"])
 +
    when 170         
 +
#      cmd_170(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"])
 +
    when 160         
 +
#      cmd_160(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:E", "@MSC:E", "@MSC:E"])
 +
    when 166         
 +
#      cmd_166(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:F", "@MSC:F", "@MSC:F"])
 +
    when 161         
 +
#      cmd_161(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:1", "@MSC:1", "@MSC:1"])
 +
    when 891         
 +
#      cmd_891(cmd);
 +
        SendIrCommand("@SUR:0H")
  
General
+
    when 587         
  #190 Enter/Go
+
#      cmd_587(cmd);
 +
identifier = cmd.params_[216]
 +
# Main Frequency "TFQ:0xxxxx" from 08700 till + 10800
 +
# Multiroom Frequency “MTF:0xxxxx“  from 08700 till + 10800
 +
# switch to tuner mode first
 +
SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"])
 +
# tune to desired frequency
 +
SendMultiZoneCommand(cmd, ["@TFQ:0"+identifier, "@MTF:0"+identifier, "@MTF:0"+identifier])
 +
log("Sending Marantz : Setting tuner frequency to "+identifier+"\n")
 +
    when 97           
 +
#      cmd_97(cmd);
 +
SendMultiZoneCommand(cmd, ["@AMT:0", "@MSM:0", "@MAM:0"])
 +
    when 313         
 +
#      cmd_313(cmd);
 +
level = cmd.params_[76]
 +
# Main volume “VOL:0xxx”  from - 99 till + 18
 +
# Multiroom Speakers "MSV:0xxx"  from - 99 till + 0
 +
# Multiroom Speakers “MVL:0xxx”  from - 99 till + 0
 +
zone = GetZone(cmd.devidto_)
 +
log("313:Set Volume Command: Got Cmd with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + " | Zone : " + zone.to_s + "\n")
 +
if ( zone == 0)
 +
      new_level = DeNormalizeVolume_MainZone(level.to_i)
 +
      temp_str = "@VOL:0"+new_level.to_s
 +
      log("SetVolumeCommand: About to send command :" + temp_str + "\n")
 +
      SendIrCommand(temp_str)
 +
elsif ( zone == 1)
 +
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
 +
      temp_str = "@MSV:0"+new_level.to_s
 +
      SendIrCommand(temp_str)
 +
elsif ( zone == 2)
 +
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
 +
      temp_str = "@MVL:0"+new_level.to_s
 +
      log("SetVolumeCommand: About to send command :" + temp_str + "\n")
 +
      SendIrCommand(temp_str)
  
Internal
+
else
#373 Private Method Listing
+
      log("SetVolumeCommand: invalid zone " + zone.to_s + ":" + zone.to_i + ". Send commands only to valid child devices!!!\n")
        def readLine() $line=String.new $index=0 cod=conn_.Recv(1, $waitTime) $line+=cod while (cod[0,1] != "\r") do if (conn_ != nil) then cod=conn_.Recv(1, $waitTime) $line += cod else log( "Can not read from serial " + "\n" ) end if( $line.size() >2 ) then log( "Temp received:" + $line + "\n" ) end end log( "Final received:" + $line + "\n" ) return $line end def log(word) logTime = Time.now timeStr = logTime.strftime("%d-%m-%Y %H:%M:%S ") print( timeStr + " " + word) if( $logFile.nil? == false ) then $logFile.print( timeStr + " " + word ) $logFile.flush() end end def readLine_avrsa() $line=String.new $index=0 cod=conn_.Recv(1, $waitTime) $line+=cod while (cod[0,1] != "\r") do if (conn_ != nil) then cod=conn_.Recv(1, $waitTime) $line += cod else log( "Can not read from serial " + "\n" ) end if( $line.size() >2 ) then log( "Temp received:" + $line + "\n" ) end end log( "Final received:" + $line + "\n" ) return $line end
+
end
#351 Process IDLE
+
        <$"@AST:?\r"$>
+
#350 Process Incoming Data
+
        # buff = readLine() # print buff,"\n" buff = conn_.RecvDelimited("\r", 100) print "Got from Marantz: ",buff,"\n" log("Got from Marantz: "+ $buff +"\n")
+
  
 +
    when 90         
 +
#      cmd_90(cmd);
 +
SendMultiZoneCommand(cmd, ["@VOL:2", "@MSV:2", "@MVL:2"])
 +
    when 89         
 +
#      cmd_89(cmd);
 +
SendMultiZoneCommand(cmd, ["@VOL:1", "@MSV:1", "@MVL:1"])
 +
    when 192         
 +
#      cmd_192(cmd);
 +
#SendMultiZoneCommand(cmd, ["@PWR:2", "@MSP:2", "@MAM:1"])
 +
  SendMultiZonePowerOnCommand(cmd, ["@AMT:1", "@MSP:2", "@MAM:1"])
 +
    when 193         
 +
#      cmd_193(cmd);
 +
#SendMultiZoneCommand(cmd, ["@PWR:1", "@MSP:1", "@MAM:2"])   
 +
  SendMultiZonePowerOffCommand(cmd, ["@AMT:2", "@MSP:1", "@MAM:2"])   
 +
    when 282 
 +
#      cmd_282(cmd);
 +
SendMultiZoneCommand(cmd, ["@SRC:3", "@MSC:3", "@MSC:3"])
  
alternative #350:
 
<pre>
 
### #350
 
while(true)
 
  @buff = conn_.Recv(128,50)
 
  if(@buff.length() == 0)
 
    break
 
  end
 
  debugin(@buff)
 
  response = @buff;
 
  avrcommand = response[1..3]
 
  avrvalue = response[5]
 
  case avrcommand
 
    when 'SRC'
 
      log('input changed: '+ avrvalue);
 
      input_param=0
 
      case avrvalue
 
        when 'D'
 
          log('Input #420: CDR')
 
          input_param=420
 
        when '4'
 
          log('Input #178: DSS')
 
          input_param=178
 
        when '2'
 
          log('Input #165: DVD')
 
          input_param=165
 
        when '3'
 
          log('Input #282: VCR-1')
 
          input_param=282
 
        when 'E'
 
          log('Input #160: TAPE')
 
          input_param=160
 
      end
 
      cmd = Command.new(device_.devid_, -1001, 1, 2, 49);
 
      cmd.params_[41] = input_param.to_s();
 
      SendCommand(cmd);
 
    when 'VOL'
 
      volume = response[5..-1].to_i();
 
      log('volume changed: ' + volume.to_s);
 
      SetDeviceDataInDB( device_.devid_, 158, volume.to_s ) # 158 = DEVICEDATA_Volume_Level_CONST
 
      cmd = Command.new(device_.devid_, -1001, 1, 2, 71);
 
      cmd.params_[30] = volume.to_s
 
      SendCommand(cmd);
 
    when 'PWR'
 
      case avrvalue
 
        when '1'
 
          log('power changed: off');
 
          cmd.params_[10] = "0";
 
        when '2'
 
          log('power changed: on');
 
          cmd.params_[10] = "1";
 
      end
 
      cmd = Command.new(device_.devid_, -1001, 1, 2, 48);
 
      SendCommand(cmd);
 
 
     else
 
     else
    log('not handling command: ' + avrcommand.to_s())
+
        log("Unmatched command for child received with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
  end
+
   
 +
   
 
end
 
end
  
### END OF #350
 
</pre>
 
  
  
#355 Process Initialize
+
###########################################################Set Tuner Frequency
        <$"@AST:F\r"$> #level of feedback <$"@VOL:0-40\r"$> # main volume <$"@MSP:2\r"$> # multi speaker <$"@MSV:0-40\r"$> # multi speaker volume $logFile = File.new("/var/log/pluto/Marantz_SR5600.log", "w") #buffer for reading from serial $line=String.new $lineIndex=0 $waitTime = 3000 #wait time in comunication
+
identifier = cmd.params_[216]
  #384 Process Receive Command For Child
+
# Main Frequency "TFQ:0xxxxx" from 08700 till + 10800
#356 Process Release
+
# Multiroom Frequency “MTF:0xxxxx“  from 08700 till + 10800
+
  
Misc
+
# switch to tuner mode first
#932 Back Down
+
SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"])
        <$"@CHL:29\r"$> <$"@CHL:2A\r"$>
+
#931 Back Up
+
        <$"@CHL:19\r"$> <$"@CHL:1A\r"$>
+
#462 Center Down
+
        <$"@CHL:24\r"$>
+
#463 Center Up
+
        <$"@CHL:14\r"$>
+
#514 Front Down
+
        <$"@CHL:22\r"$> <$"@CHL:23\r"$>
+
#515 Front Up
+
        <$"@CHL:12\r"$> <$"@CHL:13\r"$>
+
#930 SubWoofer Down
+
        <$"@CHL:2B\r"$>
+
#929 SubWoofer Up
+
        <$"@CHL:1B\r"$>
+
#644 Surround Down
+
        <$"@CHL:26\r"$> <$"@CHL:27\r"$>
+
#646 Surround Up
+
        <$"@CHL:16\r"$> <$"@CHL:17\r"$>
+
#663 Treble Down
+
        <$"@TOT:2\r"$>
+
#666 Treble Up
+
        <$"@TOT:1\r"$>
+
  
MultiRoom Line Vol
+
# tune to desired frequency
#925 MultiRoom Line Mute
+
SendMultiZoneCommand(cmd, ["@TFQ:0"+identifier, "@MTF:0"+identifier, "@MTF:0"+identifier])
        <$"@MAM:0\r"$>
+
log("Sending Marantz : Setting tuner frequency to "+identifier+"\n")
#934 MultiRoom Line Off
+
        <$"@MPW:1\r"$>
+
#933 MultiRoom Line On
+
        <$"@MPW:2\r"$>
+
#926 MultiRoom Line Set Volume
+
        <$"@MVL:0xxx\r"$>
+
#935 MultiRoom Line Toggle
+
        <$"@MPW:0\r"$>
+
#927 MultiRoom Line Vol Down
+
        <$"@MVL:2\r"$>
+
#928 MultiRoom Line Vol Up
+
        <$"@MVL:1\r"$>
+
  
MultiRoom Sound & Vo
 
#921 MultiRoom Mute
 
        <$"@MSM:0\r"$>
 
#937 MultiRoom Off
 
        <$"@MSP:1\r"$>
 
#936 MultiRoom On
 
        <$"@MSP:2\r"$>
 
#924 MultiRoom Set Volume
 
        <$"@MSV:0xxx\r"$>
 
#938 MultiRoom Toggle
 
        <$"@MSP:0\r"$>
 
#923 MultiRoom Vol Down
 
        <$"@MSV:2\r"$>
 
#922 MultiRoom Vol Up
 
        <$"@MSV:1\r"$>
 
  
Numbers
+
###########################################################313 Set Volume command
  #364 -/--/---
+
level = cmd.params_[76]
 +
# Main volume “VOL:0xxx” from - 99 till + 18
 +
# Multiroom Speakers "MSV:0xxx"  from - 99 till + 0
 +
# Multiroom Speakers “MVL:0xxx”  from - 99 till + 0
 +
zone = GetZone(cmd.devidto_)
 +
log("313:Set Volume Command: Got Cmd with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + " | Zone : " + zone.to_s + "\n")
 +
if ( zone == 0)
 +
      new_level = DeNormalizeVolume_MainZone(level.to_i)
 +
      temp_str = "@VOL:0"+new_level.to_s
 +
      log("SetVolumeCommand: About to send command :" + temp_str + "\n")
 +
      SendIrCommand(temp_str)
 +
elsif ( zone == 1)
 +
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
 +
      temp_str = "@MSV:0"+new_level.to_s
 +
      SendIrCommand(temp_str)
 +
elsif ( zone == 2)
 +
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
 +
      temp_str = "@MVL:0"+new_level.to_s
 +
      log("SetVolumeCommand: About to send command :" + temp_str + "\n")
 +
      SendIrCommand(temp_str)
  
#204 0
+
else
        <$"@SRC:F\r"$> <$"@TPR:000\r"$>
+
      log("SetVolumeCommand: invalid zone " + zone.to_s + ":" + zone.to_i + ". Send commands only to valid child devices!!!\n")
#205 1
+
end
        <$"@SRC:F\r"$> <$"@TPR:001\r"$>
+
#206 2
+
        <$"@SRC:F\r"$> <$"@TPR:002\r"$>
+
#207 3
+
        <$"@SRC:F\r"$> <$"@TPR:003\r"$>
+
#208 4
+
        <$"@SRC:F\r"$> <$"@TPR:004\r"$>
+
#209 5
+
        <$"@SRC:F\r"$> <$"@TPR:005\r"$>
+
#210 6
+
        <$"@SRC:F\r"$> <$"@TPR:006\r"$>
+
#211 7
+
        <$"@SRC:F\r"$> <$"@TPR:007\r"$>
+
#212 8
+
        <$"@SRC:F\r"$> <$"@TPR:008\r"$>
+
#213 9
+
        <$"@SRC:F\r"$> <$"@TPR:009\r"$>
+
#363 Back / Clear Entry
+
+
  
On-Screen Menu Navig
 
#240 Back / Prior Menu
 
        <$"@MNU:1\r"$>
 
#225 Display
 
  
#368 Help
 
  
#86 Menu (Show Menu)
 
        <$"@MNU:2\r"$>
 
#201 Move Down
 
        <$"@CUR:2\r"$>
 
#202 Move Left
 
        <$"@CUR:3\r"$>
 
#203 Move Right
 
        <$"@CUR:4\r"$>
 
#200 Move Up
 
        <$"@CUR:1\r"$>
 
  
Simple Control
 
#64 Skip Back - Channel/Track Lower
 
        <$"@SRC:F\r"$> <$"@TPR:2r"$>
 
#63 Skip Fwd - Channel/Track Greater
 
        <$"@SRC:F\r"$> <$"@TPR:1\r"$>
 
  
Sound & Volume
 
#230 Bass Down
 
        <$"@TOB:2\r"$>
 
#229 Bass Up
 
        <$"@TOB:1\r"$>
 
#97 Mute
 
        <$"@AMT:0\r"$>
 
#313 Set Volume
 
        <$"@VOL:0xxx\r"$>
 
#90 Vol Down
 
        <$"@VOL:2\r"$>
 
#89 Vol Up
 
        <$"@VOL:1\r"$>
 
  
Speed Ctrl
 
#125 Scan Back/Rewind
 
        <$"@SRC:F\r"$> <$"@TFQ:4\r"$>
 
#93 Scan Fwd/Fast Fwd
 
  
==== 'Add 'TV - LiveTV' device with template #1751 as child device'====  
+
###########################################################Process Initialize
 +
$DevicePower = 1
 +
SendIrCommand("@PWR:2")
 +
log("Initializing Marantz GSD Device\n")
  
Go into template #1751 for 'TV - LiveTV' device and add new entry under :
 
  
'This device is controlled via  Device:SR 5600  Category: Amps/Preamps/Receivers/Tuners    Edit      Delete'
 
  
Click on 'Edit' and this entry and be sure to tick both options :
+
SendIrCommand("@AST:F") # max level of feedback
+
Reroute Messages To Parent: 
+
Auto Create Children:
+
  
and under
+
SendIrCommand("@MPW:2") # multi room always on
Pipes Used
+
SR 5600    Input on SR 5600 Output on TV - LiveTV Pipe Flip In/Out:
+
specify to connect this device to Tuner input on SR5600.
+
  
== Adding device ==
+
SendIrCommand("@MSP:1") # turn multi room speakers off by default
 +
 
 +
SendIrCommand("@MAM:2") # mute multi room line out by default
 +
 
 +
SendIrCommand("@VOL:0-20") # default main volume -20
 +
SendIrCommand("@MSV:0-60") # default multi speaker volume
 +
SendIrCommand("@MVL:0-60") # default multi room line out volume
 +
 
 +
$ZoneStatus = Hash.new()
 +
 
 +
InitZones()
 +
ShowZonesInitialVolumes()
 +
 
 +
 
 +
#$DevicePower = 0
 +
#SendIrCommand("@PWR:1")
 +
log("Initialization of Marantz GSD Device finished - Device is powered off!!!!\n")
 +
</nowiki></pre>
 +
 
 +
==== 'TV - LiveTV' device with template #1751 as child device'====
 +
 
 +
TV- LiveTV device is automatically added as child to parent device, because I have selected it for connection to FM input. Therefore nothing more is needed to do, except support for commands that can be sent from LiveTV Orbiter screen.
 +
 
 +
=== Important device data and parameters for "Zone" template (#1867)===
 +
 
 +
I've extended that template to be useful for multizone audio devices. Basically such device should include everything that is needed to control Audio Zone (input switching, A/B switching, volume control, On/Off Commands). But bevare, those devices are embedded - that means that they don't do anything - they are just empty boxes you add to parent device for representing each audio zone. All processing of commands should be done in parent device. But using Zones, you can easily connect devices via pipes, create scenarios with sending commands to certain devices/zones etc...
 +
 
 +
Important extensions to Zone template:
 +
- added common audio inputs (so input switching can be implemented)
 +
- added commands (volume, inputs, on/off, A/B switching)
 +
- added "controlled by" category of Amps,...
 +
 
 +
Have added following command groups are used in Zone :
 +
A/B switching          (select A, select B) 
 +
Generic IO Commands (On, Off)
 +
Inputs                 (common inputs on audio receiver)
 +
Radio                 (command for tuning to certain radio frequency)
 +
 
 +
Zones are automatically added to parent device by having this on parent template :
 +
 
 +
Device Template Related
 +
#1867 Zone My Child Extra 12|2|186|Line Out
 +
#1867 Zone My Child Extra 12|1|186|Zone MultiRoom
 +
#1867 Zone My Child Extra 12|0|186|Zone Main
 +
 
 +
3 child zone devices are automatically added to parent device.
 +
 
 +
12|2 means that device data #12 (Port) will have value of 2 and that Line Out is description (data #186) of that zone 2.
 +
 
 +
== Using device ==
  
 
=== Add device based on created template ===
 
=== Add device based on created template ===
 
=== Specify COM port for it ===
 
=== Specify COM port for it ===
=== Assing it to new room ===
+
=== Assign it to new room ===
=== Specifiy Audio pipe connections to inputs on receiver ===
+
 
In my case, I connnected output of Hybrid Core and one MD to different inputs (CD and DVD). In that way, when you press play on each source, commands to setup inputs on SR5600 should be done automatically so you can hear music right away....
+
Assign also child zones to rooms or EAs.
 +
 
 +
=== Specifiy Audio pipe connections to inputs on zones ===
 +
In my case, I connnected output of Hybrid Core and one MD to different inputs (CD and DVD) and different zones. In that way, when you press play on each source, commands to setup inputs on SR5600 should be done automatically so you can hear music right away....
  
 
Now reload Router, regenerate Orbiters and new device should appear in specified room. On click you get into control screen where you can control device 'manually' beside automatic handling described above.
 
Now reload Router, regenerate Orbiters and new device should appear in specified room. On click you get into control screen where you can control device 'manually' beside automatic handling described above.
 +
 +
 +
=== Prepare Media scenarios ===
 +
 +
Beside from commands that are sent from Orbiters, you can also create various media scenarios, with On/Off, Volume, A/B, Input switching (you can for example put both (all three) output zones to same source - no sync problems !!!...
  
 
== Where the problems arise ==
 
== Where the problems arise ==
  
 
I'm describing few potential problems I'm facing in my setup. Will be happy on any opinion or guidance...
 
I'm describing few potential problems I'm facing in my setup. Will be happy on any opinion or guidance...
 +
 +
=== Proper support for connecting On screen media player (MD or Hybrid) to Amplifier ===
 +
 +
Currently it seems that media players cannot be connected to amplifier in a clean way. The problem is in routing of volume and on/off commands through audio pipe. In short, the problem is that currently you have to connect hybrid or MD to audio pipe, but when media ends in that EA, Off is sent to Xine player, but On command to Orbiter and this On command also gets propagated on pipe - so Amplifier turns on, instead of Off. Also when screen saver jumps in, there is also possibility that Off command will get to the amplifier, which is not correct if you're listening to media... There are at least few threads on forums and Mantis, if you want to read more...
 +
 +
=== Some older discussions ===
 +
 +
Below I'm leaving some older discussions about potential problems. Not sure if they still hold...
  
 
=== Proper support for MultiRoom feature ===
 
=== Proper support for MultiRoom feature ===
Line 357: Line 804:
 
[[Image:Shema audio.png]]
 
[[Image:Shema audio.png]]
  
 +
== Discussion on how to properly implement template for such device ? ==
  
 
  
== Discussion on how to properly implement template for such device ? ==
+
Currently, I've implemented such template using child Zone devices and it seems like a step in proper direction. But we will see. I'm also presenting discussion below that describes where the problem lies...
  
  

Latest revision as of 15:49, 11 July 2016

Version Status Date Updated Updated By
710 Unknown N/A N/A
810 Unknown N/A N/A
1004 Unknown N/A N/A
1204 Unknown N/A N/A
1404 Unknown N/A N/A
Usage Information

More info about device  :

This is Marantz's cheapest model that has rs232c connector and surprisingly, it has two way communication capability - that means that when user does something on receiver's button or IR remote control, you get status messages about changes...

There are few different documents about RS232 protocol on this device. This one worked on mine, luckily is ASCII based and therefore much more user friendly...

First I've closely examined existing templates for Yamaha receiver, RS232 Plasma and tried to learn things. Since there is currently no special screen prepared for control of Audio/Tuner receiver device, I decided to use 'TV - LiveTV' device with template #1751, that already has associated media screen for tuner control (it's meant for TV tuner control, but is close enough for a start)...

I have also decided to use Marantz in Multiroom configuration (7+1 output is in this case split to 4+1 output ("Zone Main") and 2ch stereo output ("Zone Multiroom"). There is also third zone - "Line Out", but this is only preamp output of Multiroom Zone, but can have separate volume/mute control. Template has currently basic support for all 3 zones. There are still few things to be added, but I'm learning Ruby slowly and have few problems, so maybe I will get some help from more experienced guys...

The whole idea of implementation is to have 3 separate zones (each represented by "Zone" child devices (extended template #1867), to whom you can connect your audio sources by audio pipes. Currently squeezebox devices and other HW players will work ok, there are some slight problems with ordinary Xine player on Onscreen Orbiter, cause whole Orbiter is connected on pipe and when the media stops playing, On command for Orbiter instead of Off for player is propagated through pipe, so your amplifier stays On for some time even after stop...


LinuxMCE Developers: Can you please add new media screen for such type of devices (http://plutohome.com/support/mantis/view.php?id=3151) and maybe even document procedure on Wiki. It would ease similar contributions from other users...

Description of needed templates

I hope that this template will be available with stock LMCE distribution, so you won't have to create that template from scratch. Template is called "SR Series MultiRoom RS232" to be different from existing template for Marantz in 7+1 configuration ("SR Series RS232"). The main difference between those templates is that this template is more complicated, cause it gives you independent controls of more zones and therefore it has a bit different logic (for example main general power is switched off only when all zones are muted, zones are switched on/off only by muting them)

For template to be functional I've made certain extensions to existing template for "Zone" that I hope will be usefull also to others...

Important device data and parameters for "SR Series MultiRoom RS232" template

Description : SR Series MultiRoom RS232
Implements DCE : yes
Command line : Generic_Serial_Device
Device Category  AV/preamps/... #103
Manufacturer Marantz

Also have added following parameters :

Device data
Current Data 	                                    Comments 	                                Default Value
#37 COM Port on PC                                                                              /dev/ttyS0 	
#76 COM Port ParityBit/Stop 	                                                                 N81
#78 COM Port BaudRate 	                                                                         B9600
#220 Process Child Commands In Pare                                                              1 (needed to have ability to send all commands to parent) 	
#157 Discrete Volume(bool)  	                                                                 1 					
#220 Process Child Commands In Pare(bool) 	

Settings are factory defaults and should't be changed (9600 baud rate, 8 bits, 1 stop bit)...

'Edit Ruby code' (on template page)

'Determining proper set of inputs'

I've added all inputs that are present on device. There is also a special input called "FM" where I connected Live TV embedded device to be able to control tuner functions (tuning/searching up/down, go to preset stations, etc...)


'Set proper set of commands'

Basically I've added command groups :

Ruby Internal Commands
Standard Receiver Command
Volume Commands

and added some needed commands (important is command to tune to certain FM frequency, so you can later add scenarios for tuning to certain FM stations....)


'Add Ruby snippets to commands'

I've created new IR/Codeset group called "Marantz SR Multiroom RS232", although I'm not sure how to handle it. Have also edited coresponding Ruby snippets for each command. Basically those are just simple strings that get send on rs232 to take proper action on device according to received command from LinuxMCE... There are also a lot of other functions that help :

- determining for which child zone command is targeted
- to "normalize" volume levels between Marantz's internal dB units and range of 0-100


Simpler commands from Ruby part of template :


  Power
 #193 Off
 	#SendMultiZoneCommand(cmd, ["@PWR:1", "@MSP:1", "@MAM:2"]) SendMultiZonePowerOffCommand(cmd, ["@AMT:2", "@MSP:1", "@MAM:2"]) 	
 
 #192 On
 	#SendMultiZoneCommand(cmd, ["@PWR:2", "@MSP:2", "@MAM:1"]) SendMultiZonePowerOnCommand(cmd, ["@AMT:1", "@MSP:2", "@MAM:1"]) 	
 
 #194 Toggle Power
 		
 
 Inputs
 #169 AM
 	SendMultiZoneCommand(cmd, ["@SRC:H", "@MSC:H", "@MSC:H"]) 	
 
 #164 Aux
 	SendMultiZoneCommand(cmd, ["@SRC:9", "@MSC:9", "@MSC:9"]) 	
 
 #172 Aux 2
 	SendMultiZoneCommand(cmd, ["@SRC:A", "@MSC:A", "@MSC:A"]) 	
 
 #162 CD
 	SendMultiZoneCommand(cmd, ["@SRC:C", "@MSC:C", "@MSC:C"]) 	
 
 #420 CDR
 	SendMultiZoneCommand(cmd, ["@SRC:D", "@MSC:D", "@MSC:D"]) 	
 
 #178 DSS
 	SendMultiZoneCommand(cmd, ["@SRC:4", "@MSC:4", "@MSC:4"]) 	
 
 #165 DVD
 	SendMultiZoneCommand(cmd, ["@SRC:2", "@MSC:2", "@MSC:2"]) 	
 
 #170 FM
 	SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"]) 	
 
 #160 Tape / Tape 1
 	SendMultiZoneCommand(cmd, ["@SRC:E", "@MSC:E", "@MSC:E"]) 	
 
 #166 Tuner
 	SendMultiZoneCommand(cmd, ["@SRC:F", "@MSC:F", "@MSC:F"]) 	
 
 #161 TV
 	SendMultiZoneCommand(cmd, ["@SRC:1", "@MSC:1", "@MSC:1"]) 	
 
 #282 VCR-1
 	SendMultiZoneCommand(cmd, ["@SRC:3", "@MSC:3", "@MSC:3"]) 	
 
 DSP Modes (Audio)
 #891 All Ch Stereo
 	#<$"@SUR:0H\r"$> SendIrCommand("@SUR:0H") 	
 
 
 #97 Mute
 	SendMultiZoneCommand(cmd, ["@AMT:0", "@MSM:0", "@MAM:0"]) 	
 
 
 #90 Vol Down
 	SendMultiZoneCommand(cmd, ["@VOL:2", "@MSV:2", "@MVL:2"]) 	
 
 #89 Vol Up
 	SendMultiZoneCommand(cmd, ["@VOL:1", "@MSV:1", "@MVL:1"]) 	
 
 Speed Ctrl
 #125 Scan Back/Rewind


More important parts with more Ruby code :

###########################################################3 Internal Methods
# To do list :
# - parsing of input messages (inputs,mute,volume,power)
# - handling of tuner (with live/TV child device)
# - to properly send events and set device current volume data 

def DecodeReceivedInfo_candidate(response)
# Examples: Mute/On/Off: @AMT:1,@MSP:2,@MAM:2,   Volume: @VOL:-25,@MSV:-56,@MVL:-56  Inputs:@MSC:2E,@SRC:22,@SRC:2E
   log("DecodeReceivedInfo1: " + response + "\n");
   avrcommand = response[1..3]
   avrvalue = response[5]
   log("DecodeReceivedInfo2: " + response + " -> Command:"+ avrcommand.to_s + " Value: " + avrvalue.to_s + "\n");

   case avrcommand
# Input Source changed
     	when 'SRC'
     		log("Main Zone Input Changed to "+ avrvalue.to_s+ "\n");
     		input_param=0
     
     		case avrvalue
     			when '1'
     				log('Main Zone Input Changed to #161: TV')
     				input_param=161
     				temp_state="Input: TV"
     			when '2'
     				log('Main Zone Input Changed to #165: DVD')
     				input_param=165
     				temp_state="Input: TV"
     			when '3'
     				log('Main Zone Input Changed to #282: VCR-1')
     				input_param=282
     				temp_state="Input: TV"
     			when '4'
     				log('Main Zone Input Changed to #178: DSS')
     				input_param=178
     				temp_state="Input: TV"
     			when '9'
     				log('Main Zone Input Changed to #164: AUX')
     				input_param=164
     				temp_state="Input: TV"
     			when 'A'
     				log('Main Zone Input Changed to #171: AUX2')
     				input_param=171
     				temp_state="Input: TV"
     			when 'C'
     				log('Main Zone Input Changed to #162: CD')
     				input_param=162
     				temp_state="Input: TV"
     			when 'D'
     				log('Main Zone Input Changed to #420: CDR')
     				input_param=420
     				temp_state="Input: TV"
     			when 'E'
     				log('Main Zone Input Changed to #160: TAPE')
     				input_param=160
     				temp_state="Input: TV"
     			when 'F'
     				log('Main Zone Input Changed to #166: TUNER')
     				input_param=166
     				temp_state="Input: TV"
     			when 'G'
     				log('Main Zone Input Changed to #170: FM')
     				input_param=160
     				temp_state="Input: TV"
     			when 'H'
     				log('Main Zone Input Changed to #169: AM')
     				input_param=169
     				temp_state="Input: TV"
     		end
#     		device_id = device_.mapPortChannel_Device_.[0.to_s]
		log("======= Determiming device ID for Zone 0 : " + device_id.to_s + "\n")
		device_.mapPortChannel_Device_.each do |key, value|
			log(key.to_s + " => " + value.to_s+ "\n")
		end
     		cmd = Command.new(device_id, -1001, 1, 2, 49);
     		cmd.params_[41] = input_param.to_s();
     		SendCommand(cmd);
     		SetDeviceDataInDB( device_id, 200, temp_state ) # 200 = DEVICEDATA_State_CONST

     	when 'VOL'
     		volume = response[5..-1].to_i();
     		volume_norm = NormalizeVolume_MainZone(volume)
     		log("Main Zone Volume Changed: " + volume.to_s + " Normalized Value: " + volume_norm.to_s + "\n");
#     		device_id = device_.mapPortChannel_Device_.[0.to_s]
		log("======= Determiming device ID for Zone 0 : " + device_id.to_s + "\n")
		device_.mapPortChannel_Device_.each do |key, value|
			log(key.to_s + " => " + value.to_s+ "\n")
		end
     		SetDeviceDataInDB( device_id, 158, volume_norm ) # 158 = DEVICEDATA_Volume_Level_CONST
     		cmd = Command.new(device_id, -1001, 1, 2, 71);
     		cmd.params_[30] = volume_norm
     		SendCommand(cmd);
     	when 'PWR'
     		case avrvalue
     			when '1'
     				log("Device Power Changed: OFF");
     				cmd.params_[10] = "0";
     				$DevicePower = 0
     			when '2'
     				log("Device Power Changed: ON");
     				cmd.params_[10] = "1";
     				$DevicePower = 1
     		end
     		cmd = Command.new(device_.devid_, -1001, 1, 2, 48);
     		SendCommand(cmd);
     	else
     		log("Yet not implemented: Handler for command: " + avrcommand.to_s)
     end
    
end     


def DecodeReceivedInfo(response)
# Examples: Mute/On/Off: @AMT:1,@MSP:2,@MAM:2,   Volume: @VOL:-25,@MSV:-56,@MVL:-56  Inputs:@MSC:2E,@SRC:22,@SRC:2E
   log("DecodeReceivedInfo1: " + response + "\n");
   avrcommand = response[1..3]
   avrvalue = response[5]
   log("DecodeReceivedInfo2: " + response + " -> Command:"+ avrcommand.to_s + " Value: " + avrvalue.to_s + "\n");

   case avrcommand
     	when 'VOL'
     		volume = response[5..-1].to_i();
     		volume_norm = NormalizeVolume_MainZone(volume)
     		log("Main Zone Volume Changed: " + volume.to_s + " Normalized Value: " + volume_norm.to_s + "\n");
#     		device_id = device_.mapPortChannel_Device_.[0.to_s]
		log("======= Determiming device ID for Zone 0 : " + device_id.to_s + "\n")
		device_.mapPortChannel_Device_.each do |key, value|
			log(key.to_s + " => " + value.to_s+ "\n")
			if (key.to_s == "0")
				device_id = value
			end
		end
     		SetDeviceDataInDB( device_id, 158, volume_norm ) # 158 = DEVICEDATA_Volume_Level_CONST
     		cmd = Command.new(device_id, -1001, 1, 2, 71);
     		cmd.params_[30] = volume_norm
     		SendCommand(cmd);
     	when 'PWR'
     		case avrvalue
     			when '1'
     				log("Device Power Changed: OFF")
     				cmd.params_[10] = "0";
     				$DevicePower = 0
     			when '2'
     				log("Device Power Changed: ON");
     				cmd.params_[10] = "1";
     				$DevicePower = 1
     		end
     		cmd = Command.new(device_.devid_, -1001, 1, 2, 48);
     		SendCommand(cmd);
     	else
     		log("Yet not implemented: Handler for command: " + avrcommand.to_s)
     end
    
end     


def ReceiveReportCommand()
	@buff = conn_.RecvDelimited("\r", 1000) 
	log("Cmd response from Marantz: " + @buff + "\n")
	log("Calling DecodeReceivedInfo: " + @buff + "\n")
	temp_resp=@buff;
	DecodeReceivedInfo(temp_resp)
	log("End of DecodeReceivedInfo: " + temp_resp + "\n")
end

def SendIrCommand(command)
        log("SendIrCommand: " + command + "\n")
	conn_.Send(command+ "\r")
        log("Sending Command: " + command + "\n")
	ReceiveReportCommand()
end

def log(line)
#          $log = File.open("/var/log/pluto/" + device_.devid_.to_s + "_Generic_Serial_Device.log", "a")
	  $log = File.open("/var/log/pluto/Marantz_SR5600.log", "a")
	  logTime = Time.now
	  timeStr = logTime.strftime("%d-%m-%Y  %H:%M:%S  ")

	  $log.puts timeStr + "(***):" + line.to_s
          $log.close
end 	

def SendMultiZoneCommand(cmd, commandsArray, commandParam="")
        log("Got Command with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
	zone = GetZone(cmd.devidto_)
	if( zone >= 0 and zone < commandsArray.size )
	        zone_desc=device_.childdevices_[cmd.devidto_].devdata_[186]
		log("Determine zone for command : " + zone_desc + "[" + zone.to_s + "]\n")
		SendIrCommand(commandsArray[zone] + commandParam.to_s)
	else
		log("SendMultiZoneCommand: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
	end
end


def SendMultiZonePowerOnCommand(cmd, commandsArray, commandParam="")
#It will Unmute Zone first and then see also global power should be turned on...
        log("Got Power On Command with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
	zone = GetZone(cmd.devidto_)
	if( zone >= 0 and zone < commandsArray.size )
	        zone_desc=device_.childdevices_[cmd.devidto_].devdata_[186]
		log("Determine zone for command : " + zone_desc + "[" + zone.to_s + "]\n")
		SendIrCommand(commandsArray[zone] + commandParam.to_s)
		$ZoneStatus[zone.to_s] = 'ON'
		log("*** Setting zone : " + zone_desc + "[" + zone.to_s + "] to ON\n")
		ShowZones()
		if ($DevicePower == 0)
			SendIrCommand("@PWR:2")
		end
		$DevicePower = 1
	elsif (zone == -1)
		if ($DevicePower == 0)
			SendIrCommand("@PWR:2")
		end
		$DevicePower = 1
		log("####### Powering device On\n")
	else
		log("SendMultiZonePowerOnCommand: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
	end
end

def SendMultiZonePowerOffCommand(cmd, commandsArray, commandParam="")
#It will Mute Zone first and then see if also global power can be turned off...
        log("Got Power Off Command with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
	zone = GetZone(cmd.devidto_)
	if( zone >= 0 and zone < commandsArray.size )
	        zone_desc=device_.childdevices_[cmd.devidto_].devdata_[186]
		log("Determine zone for command : " + zone_desc + "[" + zone.to_s + "]\n")
		SendIrCommand(commandsArray[zone] + commandParam.to_s)
		$ZoneStatus[zone.to_s] = 'OFF'
		log("*** Setting zone : " + zone_desc + "[" + zone.to_s + "] to OFF\n")
		ShowZones()
		if (($ZoneStatus["0"] == 'OFF') and ($ZoneStatus["1"] == 'OFF') and ($ZoneStatus["2"] == 'OFF'))
			SendIrCommand("@PWR:1")
			$DevicePower = 0
			log("####### All zones are muted - device is powered Off\n")
		end
	else
		log("SendMultiZonePowerOffCommand: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
	end
end


def GetZone(deviceDestination)
	if( device_.mapDevice_PortChannel_.has_key?(deviceDestination) and
		device_.mapDevice_PortChannel_[deviceDestination] != nil and
		!device_.mapDevice_PortChannel_[deviceDestination].empty? )
		return device_.mapDevice_PortChannel_[deviceDestination].to_i
	end
	
	return -1
end

def ShowZonesDebug()
	log("####### Dev 2 PortChanel\n")
	device_.mapDevice_PortChannel_.each do |key, value|
		log(key.to_s + " => " + value.to_s + "\n")
	end
	
	log("======= PortChanel 2 Dev\n")
	device_.mapPortChannel_Device_.each do |key, value|
		log(key.to_s + " => " + value.to_s+ "\n")
	end
end



def ShowZonesInitialVolumes()
	log("####### Show Initial Volume Levels for zones\n")
	device_.mapDevice_PortChannel_.each do |key, value|
	        volume = device_.childdevices_[key].devdata_[208]
		log("Zone " + value.to_s + " => " + volume.to_s + "\n")
		SetVolumeInZone(volume,value)
	end
	
end


def ShowZones()
	temp = "####### Zones Status : "
	device_.mapDevice_PortChannel_.each do |key, value|
		temp = temp + " | Zone " + value.to_s + " => " + $ZoneStatus[value] 
	end
	temp = temp + "\n"
	log(temp)
end


def SetZones(state)
	log("####### Setting all zones to " + state + "\n")
	device_.mapDevice_PortChannel_.each do |key, value|
		$ZoneStatus[value] = state
		log("Zone " + value.to_s + " => " + state + "\n")
 	end
end

def InitZones()
	log("####### Initializing all zones to OFF\n")
	device_.mapDevice_PortChannel_.each do |key, value|
		$ZoneStatus[value] = 'OFF'
		log("Zone " + value.to_s + " => " + $ZoneStatus[value] + "\n")
 	end
	log("####### Print $ZoneStatus Hash:\n")
 	$ZoneStatus.each do |key, value|
		log("Zone " + key.to_s + " => " + value.to_s + "\n")
	end
end

def SetVolumeInZone(level,zone)
# Sets Normalized Volume Level (0..100) in certain zone 
	log("SetVolumeInZone: volume: " + level.to_s + " => Zone: " + zone + "\n")

	if ( zone == "0")
		log("SetVolumeInZone0: volume: " + level.to_s + " => Zone: " + zone + "\n")
      		new_level = DeNormalizeVolume_MainZone(level.to_i)
		log("SetVolumeInZone00: volume: " + level.to_s + " => Zone: " + zone + "\n")
      		temp_str="@VOL:0"+new_level.to_s;
      		log("SetVolumeInZone: About to send command :" + temp_str + "\n")
      		SendIrCommand(temp_str)
	elsif ( zone == "1")
		log("SetVolumeInZone1: volume: " + level.to_s + " => Zone: " + zone + "\n")
      		new_level = DeNormalizeVolume_OtherZone(level.to_i)
		log("SetVolumeInZone11: volume: " + level.to_s + " => Zone: " + zone + "\n")
      		temp_str="@MSV:0"+new_level.to_s;
      		log("SetVolumeInZone: About to send command :" + temp_str + "\n")
      		SendIrCommand(temp_str)
	elsif ( zone == "2")
		log("SetVolumeInZone2: volume: " + level.to_s + " => Zone: " + zone + "\n")
      		new_level = DeNormalizeVolume_OtherZone(level.to_i)
#		log("SetVolumeInZone22: volume: " + level + " => Zone: " + zone + "\n")
      		temp_str="@MVL:0"+new_level.to_s;
      		log("SetVolumeInZone: About to send command :" + temp_str + "\n")
      		SendIrCommand(temp_str)
	else
      		log("SetVolumeInZone: invalid zone " + zone.to_s + ". Send commands only to valid child devices!!!")
	end
	log("SetVolumeInZone End: volume: " + level.to_s + " => Zone: " + zone + "\n")

end


def NormalizeVolume_MainZone(level)
# Normalizes Marantz Volume Level (-99..+10) to 0-100 boundaries for Main Zone 
	temp = (level+100)/110.0*100.0
	temp=temp.round
        log("Normalizing Main Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
	return temp
end

def NormalizeVolume_OtherZone(level)
# Normalizes Marantz Volume Level to 0-100 boundaries for Second Zone (-90..0)
	temp = ((level+90.0)/90.0)*100.0 
	temp=temp.round
        log("Normalizing Other Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
	return temp
end

def DeNormalizeVolume_MainZone(level)
# DeNormalizes volume level in 0-100 boundaries to Marantz Volume Level (-99..+10) for Main Zone 
	temp = (level/100.0)*110.0-99
	temp=temp.round
        log("DeNormalizing Main Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
	return temp
end

def DeNormalizeVolume_OtherZone(level)
# DeNormalizes volume level in 0-100 boundaries to Marantz Volume Level (-90..0) for Other Zone 
	temp = ((level/100.0)*90.0)-90.0
	temp=temp.round
        log("DeNormalizing Other Zone Volume Level from : " + level.to_s + " to " + temp.to_s + "\n")
	return temp
end












###########################################################Process Incoming Data
@buff = conn_.RecvDelimited("\r", 1000)
log("Info from Marantz: " + @buff + "\n")
temp_line=@buff
log("1Calling DecodeReceivedInfo: " + temp_line + "\n")
DecodeReceivedInfo(temp_line)
log("1End of DecodeReceivedInfo: " + temp_line+ "\n")



############################################################384 Process Receive Command For Child 
log("Received command for child with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
case cmd.id_
    when 169           
#       cmd_169(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:H", "@MSC:H", "@MSC:H"])
    when 164           
#       cmd_164(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:9", "@MSC:9", "@MSC:9"])
    when 172           
#       cmd_172(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:A", "@MSC:A", "@MSC:A"])
    when 162           
#       cmd_162(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:C", "@MSC:C", "@MSC:C"])
    when 420           
#       cmd_420(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:D", "@MSC:D", "@MSC:D"])
    when 178           
#       cmd_178(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:4", "@MSC:4", "@MSC:4"])
    when 165           
#       cmd_165(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:2", "@MSC:2", "@MSC:2"])
    when 170           
#       cmd_170(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"])
    when 160           
#       cmd_160(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:E", "@MSC:E", "@MSC:E"])
    when 166           
#       cmd_166(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:F", "@MSC:F", "@MSC:F"])
    when 161           
#       cmd_161(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:1", "@MSC:1", "@MSC:1"])
    when 891           
#       cmd_891(cmd);
        SendIrCommand("@SUR:0H")

    when 587           
#       cmd_587(cmd);
	identifier = cmd.params_[216]
 	# Main Frequency		"TFQ:0xxxxx"  from 08700 till + 10800
	# Multiroom Frequency		“MTF:0xxxxx“  from 08700 till + 10800
	# switch to tuner mode first
	SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"])
	# tune to desired frequency
	SendMultiZoneCommand(cmd, ["@TFQ:0"+identifier, "@MTF:0"+identifier, "@MTF:0"+identifier])
	log("Sending Marantz : Setting tuner frequency to "+identifier+"\n")
    when 97            
#       cmd_97(cmd);
	SendMultiZoneCommand(cmd, ["@AMT:0", "@MSM:0", "@MAM:0"])
    when 313           
#       cmd_313(cmd);
	level = cmd.params_[76]
	# Main volume 			“VOL:0xxx”  from - 99 till + 18
	# Multiroom Speakers		"MSV:0xxx"  from - 99 till + 0
	# Multiroom Speakers		“MVL:0xxx”  from - 99 till + 0
	zone = GetZone(cmd.devidto_)
	log("313:Set Volume Command: Got Cmd with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + " | Zone : " + zone.to_s + "\n")
	if ( zone == 0)
      		new_level = DeNormalizeVolume_MainZone(level.to_i)
      		temp_str = "@VOL:0"+new_level.to_s
      		log("SetVolumeCommand: About to send command :" + temp_str + "\n")
      		SendIrCommand(temp_str)
	elsif ( zone == 1)
      		new_level = DeNormalizeVolume_OtherZone(level.to_i)
      		temp_str = "@MSV:0"+new_level.to_s
      		SendIrCommand(temp_str)
	elsif ( zone == 2)
      		new_level = DeNormalizeVolume_OtherZone(level.to_i)
      		temp_str = "@MVL:0"+new_level.to_s
      		log("SetVolumeCommand: About to send command :" + temp_str + "\n")
      		SendIrCommand(temp_str)

	else
      		log("SetVolumeCommand: invalid zone " + zone.to_s + ":" + zone.to_i + ". Send commands only to valid child devices!!!\n")
	end

    when 90           
#       cmd_90(cmd);
	SendMultiZoneCommand(cmd, ["@VOL:2", "@MSV:2", "@MVL:2"])
    when 89           
#       cmd_89(cmd);
	SendMultiZoneCommand(cmd, ["@VOL:1", "@MSV:1", "@MVL:1"])
    when 192           
#       cmd_192(cmd);
	#SendMultiZoneCommand(cmd, ["@PWR:2", "@MSP:2", "@MAM:1"])
  	SendMultiZonePowerOnCommand(cmd, ["@AMT:1", "@MSP:2", "@MAM:1"])
    when 193           
#       cmd_193(cmd);
	#SendMultiZoneCommand(cmd, ["@PWR:1", "@MSP:1", "@MAM:2"])    
  	SendMultiZonePowerOffCommand(cmd, ["@AMT:2", "@MSP:1", "@MAM:2"])    
    when 282  
#       cmd_282(cmd);
	SendMultiZoneCommand(cmd, ["@SRC:3", "@MSC:3", "@MSC:3"])

    else
        log("Unmatched command for child received with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + "\n")
    
    
end



###########################################################Set Tuner Frequency
identifier = cmd.params_[216]
# Main Frequency		"TFQ:0xxxxx"  from 08700 till + 10800
# Multiroom Frequency		“MTF:0xxxxx“  from 08700 till + 10800

# switch to tuner mode first
SendMultiZoneCommand(cmd, ["@SRC:G", "@MSC:G", "@MSC:G"])

# tune to desired frequency
SendMultiZoneCommand(cmd, ["@TFQ:0"+identifier, "@MTF:0"+identifier, "@MTF:0"+identifier])
log("Sending Marantz : Setting tuner frequency to "+identifier+"\n")


###########################################################313 Set Volume command
level = cmd.params_[76]
# Main volume 			“VOL:0xxx”  from - 99 till + 18
# Multiroom Speakers		"MSV:0xxx"  from - 99 till + 0
# Multiroom Speakers		“MVL:0xxx”  from - 99 till + 0
zone = GetZone(cmd.devidto_)
log("313:Set Volume Command: Got Cmd with ID: " + cmd.id_.to_s + " from: " + cmd.devidfrom_.to_s + " to: " + cmd.devidto_.to_s + " | Zone : " + zone.to_s + "\n")
if ( zone == 0)
      new_level = DeNormalizeVolume_MainZone(level.to_i)
      temp_str = "@VOL:0"+new_level.to_s
      log("SetVolumeCommand: About to send command :" + temp_str + "\n")
      SendIrCommand(temp_str)
elsif ( zone == 1)
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
      temp_str = "@MSV:0"+new_level.to_s
      SendIrCommand(temp_str)
elsif ( zone == 2)
      new_level = DeNormalizeVolume_OtherZone(level.to_i)
      temp_str = "@MVL:0"+new_level.to_s
      log("SetVolumeCommand: About to send command :" + temp_str + "\n")
      SendIrCommand(temp_str)

else
      log("SetVolumeCommand: invalid zone " + zone.to_s + ":" + zone.to_i + ". Send commands only to valid child devices!!!\n")
end







###########################################################Process Initialize
$DevicePower = 1
SendIrCommand("@PWR:2")
log("Initializing Marantz GSD Device\n")



SendIrCommand("@AST:F") # max level of feedback

SendIrCommand("@MPW:2") # multi room always on

SendIrCommand("@MSP:1") # turn multi room speakers off by default

SendIrCommand("@MAM:2") # mute multi room line out by default

SendIrCommand("@VOL:0-20") # default main volume -20
SendIrCommand("@MSV:0-60") # default multi speaker volume
SendIrCommand("@MVL:0-60") # default multi room line out volume

$ZoneStatus = Hash.new()

InitZones()
ShowZonesInitialVolumes()


#$DevicePower = 0
#SendIrCommand("@PWR:1")
log("Initialization of Marantz GSD Device finished - Device is powered off!!!!\n")

'TV - LiveTV' device with template #1751 as child device'

TV- LiveTV device is automatically added as child to parent device, because I have selected it for connection to FM input. Therefore nothing more is needed to do, except support for commands that can be sent from LiveTV Orbiter screen.

Important device data and parameters for "Zone" template (#1867)

I've extended that template to be useful for multizone audio devices. Basically such device should include everything that is needed to control Audio Zone (input switching, A/B switching, volume control, On/Off Commands). But bevare, those devices are embedded - that means that they don't do anything - they are just empty boxes you add to parent device for representing each audio zone. All processing of commands should be done in parent device. But using Zones, you can easily connect devices via pipes, create scenarios with sending commands to certain devices/zones etc...

Important extensions to Zone template:

- added common audio inputs (so input switching can be implemented)
- added commands (volume, inputs, on/off, A/B switching)
- added "controlled by" category of Amps,...

Have added following command groups are used in Zone :

A/B switching           (select A, select B)  	
Generic IO Commands 	(On, Off)
Inputs 	                (common inputs on audio receiver)
Radio 	                (command for tuning to certain radio frequency)

Zones are automatically added to parent device by having this on parent template :

Device Template Related
#1867 	Zone 	My Child 	Extra 	12|2|186|Line Out 	
#1867 	Zone 	My Child 	Extra 	12|1|186|Zone MultiRoom 	
#1867 	Zone 	My Child 	Extra 	12|0|186|Zone Main 	

3 child zone devices are automatically added to parent device.

12|2 means that device data #12 (Port) will have value of 2 and that Line Out is description (data #186) of that zone 2.

Using device

Add device based on created template

Specify COM port for it

Assign it to new room

Assign also child zones to rooms or EAs.

Specifiy Audio pipe connections to inputs on zones

In my case, I connnected output of Hybrid Core and one MD to different inputs (CD and DVD) and different zones. In that way, when you press play on each source, commands to setup inputs on SR5600 should be done automatically so you can hear music right away....

Now reload Router, regenerate Orbiters and new device should appear in specified room. On click you get into control screen where you can control device 'manually' beside automatic handling described above.


Prepare Media scenarios

Beside from commands that are sent from Orbiters, you can also create various media scenarios, with On/Off, Volume, A/B, Input switching (you can for example put both (all three) output zones to same source - no sync problems !!!...

Where the problems arise

I'm describing few potential problems I'm facing in my setup. Will be happy on any opinion or guidance...

Proper support for connecting On screen media player (MD or Hybrid) to Amplifier

Currently it seems that media players cannot be connected to amplifier in a clean way. The problem is in routing of volume and on/off commands through audio pipe. In short, the problem is that currently you have to connect hybrid or MD to audio pipe, but when media ends in that EA, Off is sent to Xine player, but On command to Orbiter and this On command also gets propagated on pipe - so Amplifier turns on, instead of Off. Also when screen saver jumps in, there is also possibility that Off command will get to the amplifier, which is not correct if you're listening to media... There are at least few threads on forums and Mantis, if you want to read more...

Some older discussions

Below I'm leaving some older discussions about potential problems. Not sure if they still hold...

Proper support for MultiRoom feature

Device supports separate stereo device on two back channels. That means that with enabling multiroom feature, basically you get two devices (one 4+1 and other 2 channels) that can have separate or same sources and different volume levels. I'm not sure how to properly setup support for such feature - will try to add another child tuner and set it up to control only second separate channel. But it seems that I cannot get two screens for two tuners/zones in one zone, but as child devices they need to be in same zone (as I was advised from LinuxMCE guys or am I missing something).

Cannot add device to Entertainment areas in same room

I have SR5600 assigned to room. Assigning it to separate entertainment area in one of the rooms didn't work (menus didn't appear on Orbiters). Also I should put two child devices (tuners) into separate audio entities, but that would probably not work at this time...

I'm not sure what is the real problem and what is proper solution. I'll kindly ask LinuxMCE guys to guide me here....

Pipes can be connected only to one device

It seems logical, but in case of such devices it's also restriction. I have Hybrid and MD output connected to one input on receiver (although have virtually two devices and would like to have an option to be able to connect two audio pipes from one source). There is also Y connection splitting line audio signal from MD to TV and receiver. Also pipes feature of automatic handling of routing (if you for instance press play on MD, then receiver will be automatically switched to proper input, so you can hear music) can sometimes become restriction. For instance if I use two separate inputs, then hybrid is assigned to one of them and volume control will change main volume and play/stop will reroute always to hard-coded route, regardless of current state, where it might be better rerouted to second device output, cause first one is occupied with Movie....

Pipes and automatic routing is not always a good thing

For instance, user is listening to audio, then he decides to switch manually receiver to FM station. MD or hybrid keeps playing its music and shuts receiver off when it finishes... If we want to properly deal with this situation, we should have two way communication and a lot of code to sense user actions and set everything according to that - but that's a lot more of work to do....


This is schema for my setup and I'd kindly ask for further guidance. There are quite few potential problems with more sophisticated setups, but I feel that this will be common practical situation in deploying LinuxMCE system...

Shema audio.png

Discussion on how to properly implement template for such device ?

Currently, I've implemented such template using child Zone devices and it seems like a step in proper direction. But we will see. I'm also presenting discussion below that describes where the problem lies...


After a year or so, it is not clear to me how to properly implement template for such device that includes all sorts of "embedded devices".

Let me start with basic description of capabilities :

1. Outputs

A. device as single audio output

 A.1 7+1 channel amplified output
 A.2 Line out that has same music as A.1, but can be swithced on/off and volume controlled separately with serial commands

B. device as multiroom audio output (two separate and controlable outputs) - this is how I use it at the moment to feed 2 audio zones)

 A.1 5+1 channel amplified output
 A.1 2 channel amplified output on last two speakers terminals with own commands for volume,source and other control...
 A.3 Line out that has same music as A.1, but can be swithced on/off and volume controlled separately with serial commands 

So basically to cover both cases I have 3 possible outputs :

 O.1 normal main audio output (either 7+1 if A and 5+1 if B)
 O.2 secondary stereo amplified output (last two outputs from A.1 are made as separate amplified stereo output with its own serial commands, volume and source control..)
 O.3 Line out that has same music as O.1, but can be switched on/off and volume controlled separately with own serial commands, so could be used for externally amplified replication of main output...

Basic distinction is that all 3 possible outputs have separate serial commands for volume and source control(not O3) etc...

2. Inputs

Outputs O.1 and O.2 can select one of possible sources independently - (I'm not sure if they can select separate FM stations on Tuner input) - so basically this is true multi channel audio feature. If they select same source, then same music is heard on each... But again serial commands for selecting inputs differ for each output....

LMCE has already prepared FM and AM Tuner devices templates (which I don't understand quite well, but no docs available), but I'm not sure if they are usable in such situation.

3. How to make usable template out of this ?

What I'm currently thinking is : - Marantz receiver being parent device - have child devices for each output (O.1-O.3), each from different template, cause they have separate commands for each

But questions arise : - each output could be placed into separate audio zone - but I'm not sure if this can be done with children of same parent ? - how to dispatch commands to each child ? - is it convenient to use tuner devices as well ?

And probably there are some more problems to be solved.

Any opinion ?

(to be expanded)