The following page was printed from RemoteCentral.com:
| Topic: | DBX ZonePro This thread has 7 replies. Displaying all posts. |
|
| Post 1 made on July 19, 2019 at 18:46 |
|
Joined: Posts: | July 2009 1,285 |
|
|
An insanely cruel barely documented protocol. I've got the string calculator and know how to bring up the sniffer from the GUI programming software. I want basic functions. Volume control, mute and feedback from those for my CF controller. I've been working on a JS driver and have mute and ramped volume control function. The string calculator only calculates the most basic functions and trying to decipher which codes being sent back and forth are relevant is making my eyes bleed. Does anyone, per chance, know how to register for mute feedback for example? If I had one working command to register for and request/trigger feedback on one specific function (mute for example) I would be off to the races. var ZonePro = function() { var self = { system: "", model: "", join: -1, feedback : "", debug: 1, zone1 : ["01","05","00","10"], zone2 : ["01","05","01","11"], zone3 : ["01","05","02","12"], zone4 : ["01","05","03","13"], }; self.setup = function(system, feedback) { self.log("Creating " + system + " " + feedback ); self.system = system; self.feedback = feedback; }; self.initialize = function() { self.log("init"); CF.watch(CF.FeedbackMatchedEvent, self.system, self.feedback, self.ProcessFeedback); self.sendHeartbeat(); }; /////////////////////////////// // VOLUME FUNCTIONS // /////////////////////////////// self.setVolume = function(zone, volume) { switch (zone) { case 1: self.setZoneVolume(self.zone1, volume); break; case 2: self.setZoneVolume(self.zone2, volume); break; case 3: self.setZoneVolume(self.zone3, volume); self.setZoneVolume(self.zone4, volume); break; } }; self.setZoneVolume = function(zone, volume) { var commandarray = ["F0","64","00","01","00","00","00","1C","00","33"]; var fillarray = ["00","30"]; var endarray = ["01","00","00","00","00","01","00","01","03","00"]; commandarray = commandarray.concat(zone, fillarray, zone, endarray); commandarray.push((parseInt(volume) * 2 + 181).toString(16)); commandarray.push(self.checksum(commandarray)); self.log(commandarray); self.sendCommand(self.hexify(commandarray)); }; /////////////////////////////// // MUTE FUNCTIONS // /////////////////////////////// self.muteOn = function() { self.log("Mute"); self.muteZoneOn(1, "01"); self.muteZoneOn(2, "01"); self.muteZoneOn(3, "01"); self.muteZoneOn(4, "01"); }; self.muteOff = function() { self.log("UnMute"); self.muteZoneOn(1, "00"); self.muteZoneOn(2, "00"); self.muteZoneOn(3, "00"); self.muteZoneOn(4, "00"); }; self.muteZoneOn = function(zone, mute) { var commandarray = ["F0","64","00","01","00","00","00","1B","00","33"]; var fillarray = ["00","30"]; var endarray = ["01","00","00","00","00","01","00","02","01"]; var target = ""; switch (zone) { case 1: target = self.zone1; break; case 2: target = self.zone2; break; case 3: target = self.zone3; break; case 4: target = self.zone4; break; } commandarray = commandarray.concat(target, fillarray, target, endarray); commandarray.push(mute); commandarray.push(self.checksum(commandarray)); self.sendCommand(self.hexify(commandarray)); }; /////////////////////////////// // FEEDBACK // /////////////////////////////// self.ProcessFeedback = function(feedbackname, feedbackstring) { self.log("fb " + feedbackname + " " + feedbackstring); // hahahah yea right return;
}; /////////////////////////////// // INTERNAL HELPER FUNCTIONS // /////////////////////////////// self.sendHeartbeat = function() { // Heartbeat F0 8C self.log("heartbeat"); self.sendCommand("\xF0\x8C"); };
self.hexify = function( array ) { var string = ""; for ( var i = 0; i < array.length; i++) { string = string + String.fromCharCode(parseInt(array[i],16)); } return string; }; self.checksum = function(dbx) { var ccit = ["5E","BC","E2","61","3F","DD","83","C2","9C","7E","20","A3","FD","1F","41","9D" ,"C3","21","7F","FC","A2","40","1E","5F","01","E3","BD","3E","60","82","DC","23", "7D","9F","C1","42","1C","FE","A0","E1","BF","5D","03","80","DE","3C","62","BE", "E0","02","5C","DF","81","63","3D","7C","22","C0","9E","1D","43","A1","FF","46"," 18","FA","A4","27","79","9B","C5","84","DA","38","66","E5","BB","59","07","DB"," 85","67","39","BA","E4","06","58","19","47","A5","FB","78","26","C4","9A","65"," 3B","D9","87","04","5A","B8","E6","A7","F9","1B","45","C6","98","7A","24","F8"," A6","44","1A","99","C7","25","7B","3A","64","86","D8","5B","05","E7","B9","8C"," D2","30","6E","ED","B3","51","0F","4E","10","F2","AC","2F","71","93","CD","11"," 4F","AD","F3","70","2E","CC","92","D3","8D","6F","31","B2","EC","0E","50","AF"," F1","13","4D","CE","90","72","2C","6D","33","D1","8F","0C","52","B0","EE","32"," 6C","8E","D0","53","0D","EF","B1","F0","AE","4C","12","91","CF","2D","73","CA"," 94","76","28","AB","F5","17","49","08","56","B4","EA","69","37","D5","8B","57"," 09","EB","B5","36","68","8A","D4","95","CB","29","77","F4","AA","48","16","E9"," B7","55","0B","88","D6","34","6A","2B","75","97","C9","4A","14","F6","A8","74"," 2A","C8","96","15","4B","A9","F7","B6","E8","0A","54","D7","89","6B","35"]; var bcc = "FF"; for (var i = 1; i < dbx.length; i++ ) { var dbx1 = parseInt(dbx[i],16); var bcc1 = parseInt(bcc,16); var bcc = ccit[(bcc1^dbx1)-1]; } return bcc; }; self.sendCommand = function (command) { CF.send("Moxa_ZonePro", command + "\n"); }; // Only allow logging calls when CF is in debug mode - better performance in release mode this way self.log = function(msg) { if (CF.debug && self.debug) { CF.log("ZonePro: " + msg); } }; return self; }; CF.modules.push({ name: "DBX ZonePro", object: ZonePro, version: 1.0 });
Last edited by Fiasco on July 19, 2019 20:52.
|
Pump House on Facebook: [Link: facebook.com] |
|
| OP | Post 2 made on July 19, 2019 at 20:51 |
|
Joined: Posts: | July 2009 1,285 |
|
|
Doh, kept googling and found the basic zonepror232 doc sheet that's easy to find via google that I already had and then started backtracking up the websites directory tree and found a much better 232 doc inside a zip file where the protocol is fleshed out better. I think I'm on my way
|
Pump House on Facebook: [Link: facebook.com] |
|
| OP | Post 3 made on July 22, 2019 at 06:48 |
|
Joined: Posts: | July 2009 1,285 |
|
|
I have volume and mute feedback what a pita.
|
Pump House on Facebook: [Link: facebook.com] |
|
| OP | Post 4 made on March 21, 2024 at 17:57 |
|
Joined: Posts: | July 2009 1,285 |
|
|
I got a zonepro for my house so I picked back up my ZP script and started workign on it again. I forgot how brutal the documentation of the protocol was. There's an engineer sitting around somewhere jerking off every time he thinks about someone trying to integrate a zonepro. From the protocol documentation: "The dbx ZonePRO is designed for 1-way control from a 3rd party controller. We do not offer a full-duplex protocol guide to our end users. The only exception to this rule is if the user downloads and uses the AMX and Crestron modules from our website www.dbxpro.com . We have worked with these two manufacturers to provide reliable full-duplex (2-way) controllers for our customers." Yea right. I wouldn't want to write the documentation for feedback either. After hours of making single adjustements to the zonepro then comparing generated hex codes I've started identifying a lot of the virtual devices. I've got all the zone RTE's completely mapped (volume, source and mute is about all most people would want) including source, priority, priority volume, page, page volume, mute master/source and all the ducking sliders working with two way feedback.
|
Pump House on Facebook: [Link: facebook.com] |
|
| OP | Post 5 made on March 21, 2024 at 18:05 |
|
Joined: Posts: | July 2009 1,285 |
|
|
var ZonePro = function() { �� �var module = { �� ��� �system�� ��� �: "", �� ��� �model�� ��� �: "", �� ��� �join�� ��� �: -1, �� ��� �feedback�� ��� �: "", �� ��� �debug�� ��� �: 1, �� ��� �disco����� ��� �: ["ff","ff"], �� ��� �zone1 ��� ��� �: ["00","00","00","00"], �� ��� �zone2 ��� ��� �: ["00","00","00","00"], �� ��� �zone3 ��� ��� �: ["00","00","00","00"], �� ��� �zone4 ��� ��� �: ["00","00","00","00"], �� ��� �buffer�� ��� �: [], ��������������� node�� ��� �: ["8A"],� // 640m default node is 138/8A ��������������� framestart �� �: ["F0", "64"], ��������������� framecount�� �: ["00"], ��������������� version�� ��� �: ["01"], ��������������� address�� ��� �: ["AB", "CD"],� // Pick a hex address to identify yourself to the zonepro�� ��������������� recipient�� �: ["FF", "FF"], ��������������� zone1join�� �: 0, ��������������� zone2join�� �: 0, ��������������� zone3join�� �: 0, ��������������� zone4join�� �: 0, �� �}; �� // Output 1 Address 20 0 5 1 // Output 2 Address 21 1 5 1 // Output 3 Address 22 2 5 1 // Output 4 Address 23 3 5 1 // zonepro node address 48 // router 1 id 27 b0 16 b1 0 b2 5 b3 1 posb0 0 posb1 5 // router 2 id 27 b0 17 b1 1 b2 5 b3 1 posb0 1 posb1 5 // router 3 id 27 b0 18 b1 2 b2 5 b3 1 posb0 2 posb1 5 // router 4 id 27 b0 19 b1 3 b2 5 b3 1 posb0 3 posb1 5 // msgid 0113 subscribeall // msgid 0114 unsubscribeall // msgid 9001 recall scene // msgid 0100 multisvset // msgid 0000 disco // msgid 0004 info // msgid 0103 get message // msgid 011e get object list // flags bit 0 reqack // flags bit 1 ack // flags bit 2 info // flags bit 3 error // flags bit 4 event // flags bit 8-15 hop count //Frame Start UBYTE 0x64 //Frame Count UBYTE 0x00 //VERSION UBYTE 0x01 //LEN ULONG Length of entire packet (not including FS FC, CS) //SRC UWORD:ULONG [Device : Object] //DEST UWORD:ULONG [Device : Object] //MSG_ID UWORD Specific type of command issued //FLAGS UWORD (there is no guaranteed bit) //(Payload) //Checksum UBYTE CCITT-8 (over FS, FC, Header, Payload) // �� �[FRAMESTART]�� �[FRAMECOUNT]�� �[VERSION]�� �[LEN]�� ��� ��� �[SRC.RTE]�� �[NODE]�� �[DEST.RTE]�� �[MSGID]�� ��� �[FLAGS]�� ��� �[PAYLOAD]�� �[CHECKSUM] // F0�� �64�� ��� �00�� ��� �01�� ��� �00,00,00,1B�� �00,33 �� �01,05,00,15�� �00,8A�� �01,05,00,15�� �01,00,00,00,00,01,00,02,01�� �01�� ��� �7B
�� �module.setup = function(system, feedback, node, debug) { �� ��� ��� ��� �module.system = system; �� ��� ��� ��� �module.feedback = feedback; �� ��� ��� ��� �module.node = node.toString(16); �� ��� ��� ��� �module.node = "8A"; �� ��� ��� ��� �module.debug = debug; �� ��� ��� �module.log("Setup System " + system + " Feedback " + feedback + " DBXNode " + node + " Debug " + debug ); �� ��� ��� �� �}; �� �� �� �// in zone pro designer, select the RTE and hit ctrl+shift+o to get the 4 address numbers (b0, b1, b2, b3) and call the RTE functions to assign them. �� �module.setupRTE = function( rte, array ) { �� ��� �// create the base join number for GUI elements �� ��� �var joinnumber = ""; �� ��� �for ( var i = 0; i < array.length; i++ ) { �� ��� ��� �joinnumber = joinnumber + array[i]; �� ��� �} �� ��� �module.log("RTE" + rte + " " + "Mute Join Number " + joinnumber);
�� ��� �// convert address to hex �� ��� �for ( var i = 0; i < array.length; i++ ) { �� ��� ��� �array[i] = array[i].toString(16); �� ��� ��� �// pad hex value with leading 0 if necessary �� ��� ��� �if ( array[i].length < 2 ) { �� ��� ��� ��� �array[i] = "0" + array[i]; �� ��� ��� �} �� ��� �} �� ��� �// assign it to the zones �� ��� �switch (rte) { �� ��� ��� �case 1: �� ��� ��� ��� �module.zone1 = array.reverse(); �� ��� ��� ��� �module.log("Setup RTE1 " + module.zone1 ); �� ��� ��� ��� �module.zone1join = joinnumber; �� ��� ��� �break; �� ��� ��� �case 2: �� ��� ��� ��� �module.zone2 = array.reverse(); �� ��� ��� ��� �module.log("Setup RTE2 " + module.zone2 ); �� ��� ��� ��� �module.zone2join = joinnumber; �� ��� ��� �break; �� ��� ��� �case 3: �� ��� ��� ��� �module.zone3 = array.reverse(); �� ��� ��� ��� �module.log("Setup RTE3 " + module.zone3 ); �� ��� ��� ��� �module.zone3join = joinnumber; �� ��� ��� �break; �� ��� ��� �case 4: �� ��� ��� ��� �module.zone4 = array.reverse(); �� ��� ��� ��� �module.log("Setup RTE4 " + module.zone4 ); �� ��� ��� ��� �module.zone4join = joinnumber; �� ��� ��� �break;�� �� ��� ��� �default: �� ��� ��� ��� �module.log("ERROR - invalid RTE number should be 1-4"); �� ��� ��� �break; �� ��� �} �� �} �� �� �module.initialize = function() { �� ��� �module.log("Start watching freedback on " + module.system + " " + module.feedback); �� ��� �CF.watch(CF.FeedbackMatchedEvent, module.system, module.feedback, module.ProcessFeedback); �� ��� �module.requestAddress(); �� ��� �module.sendDisco(); �� ��� �setInterval(function(){ module.sendHeartbeat();}, 1000); �� ��� �setInterval(function(){ module.sendDisco();} , 10000); �� ��� �module.log("Initialized...\n"); �� �}; �� �� �module.requestAddress = function() { �� ��� �var framestart�� ��� �= module.framestart;�� �� ��� �var framecount �� ��� �= module.framecount; �� ��� �var version�� ��� �= module.version; �� ��� �var length �� ��� �= ["00", "00", "00", "2F"]; �� ��� �var source �� ��� �= [module.address[0], module.address[1], "00", "00", "00", "00"]; �� ��� �var destination �� �= ["ff", "ff", "00", "00", "00", "00"]; �� ��� �var messageid�� ��� �= ["00", "00"]; �� ��� �var flags�� ��� �= ["05", "00"]; �� ��� �var payload �� ��� �= [module.address[0], module.address[1], "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00"]; �� ��� �var commandarray �� �=� []; �� ��� �commandarray = commandarray.concat( framestart, framecount, version, length, source, destination, messageid, flags, payload); ��� �� ��� �commandarray.push(module.checksum(commandarray)); �� ��� �module.sendCommand(commandarray, "Request Address: ", 0); �� �}�� �� �� �module.sendDisco = function() { �� ��� �var framestart�� ��� �= module.framestart;�� �� ��� �var framecount �� ��� �= module.framecount; �� ��� �var version�� ��� �= module.version; �� ��� �var length �� ��� �= ["00", "00", "00", "2F"]; �� ��� �var source �� ��� �= [module.address[0], module.address[1], "00", "00", "00", "00"]; �� ��� �var destination �� �= ["ff", "ff", "00", "00", "00", "00"]; �� ��� �var messageid�� ��� �= ["00", "00"]; �� ��� �var flags�� ��� �= ["05", "00"]; �� ��� �var payload �� ��� �= [module.address[0], module.address[1], "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00"]; �� ��� �var commandarray �� �= []; �� ��� �commandarray = commandarray.concat( framestart, framecount, version, length, source, destination, messageid, flags, payload); ��� �� ��� �commandarray.push(module.checksum(commandarray)); �� ��� �module.sendCommand(commandarray, "Send Disco: ", 0); �� �};�� �� �� �module.subscribe = function( zone ) { �� ��� �var framestart�� ��� �= module.framestart;�� �� ��� �var framecount �� ��� �= module.framecount; �� ��� �var version�� ��� �= module.version; �� ��� �var length �� ��� �= ["00", "00", "00", "20"]; �� ��� �var source �� ��� �= [module.address[0], module.address[1], zone[0], zone[1], zone[2], zone[3]]; �� ��� �var destination �� �= ["00", module.node, zone[0], zone[1], zone[2], zone[3]]; �� ��� �var messageid�� ��� �= ["01", "13"]; �� ��� �var flags�� ��� �= ["00", "00"]; �� ��� �var payload �� ��� �= [module.address[0], module.address[1], zone[0], zone[1], zone[2], zone[3], "01", "00", "00", "00", "01"]; �� ��� �var commandarray �� �= []; �� ��� �commandarray = commandarray.concat( framestart, framecount, version, length, source, destination, messageid, flags, payload); ��� �� ��� �commandarray.push(module.checksum(commandarray)); �� ��� �module.sendCommand(commandarray, "Subscribe to Zone: ", 0);�� �� �}; �� �module.getVDList = function() { �� ��� �var framestart�� ��� �= module.framestart;�� �� ��� �var framecount �� ��� �= module.framecount; �� ��� �var version�� ��� �= module.version; �� ��� �var length �� ��� �= ["00", "00", "00", "19"]; �� ��� �var source �� ��� �= [module.address[0], module.address[1], "00", "00", "00", "00"]; �� ��� �var destination �� �= ["00", module.node, "00", "00", "00", "00"]; �� ��� �var messageid�� ��� �= ["01", "1a"]; �� ��� �var flags�� ��� �= ["05", "00"]; �� ��� �var payload �� ��� �= ["00", "02", "00", "00"]; �� ��� �var commandarray �� �= []; �� ��� �commandarray = commandarray.concat( framestart, framecount, version, length, source, destination, messageid, flags, payload); ��� �� ��� �commandarray.push(module.checksum(commandarray)); �� ��� �module.sendCommand(commandarray, "Get VD List: ", 1);�� ��� �� �} �� �module.describeVD = function() { �� ��� �var framestart�� ��� �= module.framestart;�� �� ��� �var framecount �� ��� �= module.framecount; �� ��� �var version�� ��� �= module.version; �� ��� �var length �� ��� �= ["00", "00", "00", "15"]; �� ��� �var source �� ��� �= [module.address[0], module.address[1], module.zone1[0], module.zone1[1], module.zone1[2], module.zone1[3]]; �� ��� �var destination �� �= ["00", module.node, module.zone1[0], module.zone1[1], module.zone1[2], module.zone1[3]]; �� ��� �var messageid�� ��� �= ["01", "19"]; �� ��� �var flags�� ��� �= ["00", "01"]; �� ��� �var commandarray �� �= []; �� ��� �module.log(module.zone1 + " " + module.zone1[3]); �� ��� �commandarray = commandarray.concat( framestart, framecount, version, length, source, destination, messageid, flags); ��� �� ��� �commandarray.push(module.checksum(commandarray)); �� ��� �module.sendCommand(commandarray, "Describe VD: ", 1); �� �}�� ��� �� ��� �� ��� �� �/////////////////////////////// �� �// VOLUME FUNCTIONS��������� // �� �/////////////////////////////// �� �module.setVolume = function(zone, volume) { �� ��� �var commandarray = ["F0","64","00","01","00","00","00","1C","00","33"]; �� ��� �var nodearray �� � = ["00", module.node]; �� ��� �var msgidarray�� � = ["01","00","00","00","00","01","00","01","03","00"]; �� ��� �var target = ""; �� ��� �switch (zone) { �� ��� ��� �case 1: �� ��� ��� �target = module.zone1; �� ��� ��� �break; �� ��� ��� �case 2: �� ��� ��� �target = module.zone2; �� ��� ��� �break; �� ��� ��� �case 3: �� ��� ��� �target = module.zone3; �� ��� ��� �break; �� ��� ��� �case 4: �� ��� ��� �target = module.zone4; �� ��� ��� �break; �� ��� �} �� ��� �commandarray = commandarray.concat(target, nodearray, target, msgidarray); �� ��� �commandarray.push(volume); �� ��� �commandarray.push(module.checksum(commandarray)); �� ��� �module.sendCommand(commandarray, "zone " + zone + " volume " + volume ); �� �}; �� �module.muteZone = function(zone, join) { �� ��� �CF.getJoin(join, function(join,value) {�� ��� �� ��� ��� �if ( value == 1 ) { �� ��� ��� ��� �value = 0; �� ��� ��� �} else { �� ��� ��� ��� �value = 1; �� ��� ��� �} �� ��� ��� �// zone 1 mute���� F0 64 00 01 00 00 00 1B 00 33 01 05 00 14 00 8A 01 05 00 14 01 00 00 00 00 01 00 02 01 01 81 �� ��� ��� �// zone 2 unmute�� F0 64 00 01 00 00 00 1B 00 33 01 05 00 14 00 8A 01 05 00 14 01 00 00 00 00 01 00 02 01 00 DF �� ��� ��� �module.log("Zone " + zone + " mute " + value ); �� ��� ��� �var commandarray = ["F0","64","00","01","00","00","00","1B","00","33"]; �� ��� ��� �var nodearray �� � = ["00", module.node]; �� ��� ��� �var msgidarray �� � = ["01","00","00","00","00","01","00","02","01"];�� �� ��� ��� �var target = ""; �� ��� ��� �switch (zone) { �� ��� ��� ��� �case 1: �� ��� ��� ��� �target = module.zone1; �� ��� ��� ��� �break; �� ��� ��� ��� �case 2: �� ��� ��� ��� �target = module.zone2; �� ��� ��� ��� �break; �� ��� ��� ��� �case 3: �� ��� ��� ��� �target = module.zone3; �� ��� ��� ��� �break; �� ��� ��� ��� �case 4: �� ��� ��� ��� �target = module.zone4; �� ��� ��� ��� �break; �� ��� ��� �} �� ��� ��� �commandarray = commandarray.concat(target, nodearray, target, msgidarray); �� ��� ��� �commandarray.push("0" + value); �� ��� ��� �commandarray.push(module.checksum(commandarray)); �� ��� ��� �module.sendCommand(commandarray, "zone " + zone + " mute " + value ); �� ��� �}); �� �}; �� �module.setInput = function(zone, input) { �� ��� �var commandarray = ["F0","64","00","01","00","00","00","1B","00","33"]; �� ��� �var nodearray �� � = ["00", module.node]; �� ��� �var msgidarray �� � = ["01","00","00","00","00","01","00","00","01"];�� �� ��� �var target = ""; �� ��� �switch (zone) { �� ��� ��� �case 1: �� ��� ��� �target = module.zone1; �� ��� ��� �break; �� ��� ��� �case 2: �� ��� ��� �target = module.zone2; �� ��� ��� �break; �� ��� ��� �case 3: �� ��� ��� �target = module.zone3; �� ��� ��� �break; �� ��� ��� �case 4: �� ��� ��� �target = module.zone4; �� ��� ��� �break; �� ��� �} �� ��� �commandarray = commandarray.concat(target, nodearray, target, msgidarray);�� ��� ��� �� ��� �commandarray.push("0" + input); �� ��� �commandarray.push(module.checksum(commandarray)); �� ��� �module.sendCommand(commandarray, "zone " + zone + " input " + input + " - ");�� �� �} �� �� �� �� // current receiving from disco 64 - 0 - 1 - 0 0 0 2f - 0 8a - 0 0 0 0 - 1c 30 0 0 0 0 0 0 0 4 0 8a 5 0 10 0 0 0 0 0 0 0 0 0 0 0 f d7 1 5 8a 10 0 0 0 e8 // �� �[FRAMESTART]�� �[FRAMECOUNT]�� �[VERSION]�� �[LEN]�� ��� ��� �[SRC.RTE]�� �[NODE]�� �[DEST.RTE]�� �[MSGID]�� ��� �[FLAGS]�� ��� �[PAYLOAD]�� �[CHECKSUM] // F0�� �64�� ��� �00�� ��� �01�� ��� �00,00,00,1B�� �00,33 �� �01,05,00,15�� �00,8A�� �01,05,00,15�� �01,00,00,00,00,01,00,02,01�� �01�� ��� �7B // 4 10 17 26 37 45 // send disco no address // 01 00 00 00 2f 30 1c 00 00 00 00 ff ff 00 00 00 00 00 00 05 00 1c 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // send disco w/ address // 01 00 00 00 2f 30 1c 00 00 00 00 00 30 00 00 00 00 00 00 05 04 1c 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // rec disco no address // 01 00 00 00 2f 00 30 00 00 00 00 ff ff 00 00 00 00 00 00 00 04 00 30 37 00 10 00 00 00 00 00 00 00 00 00 00 00 0f d7 02 20 51 10 00 00 00 04 // rec disco w/ address // 01 00 00 00 2f 00 30 00 00 00 00 30 1c 00 00 00 00 00 00 00 04 00 30 70 00 10 00 00 00 00 00 00 00 00 00 00 00 0f d7 02 20 51 10 00 00 00 04 �� �/////////////////////////////// �� �// FEEDBACK����������������� // �� �/////////////////////////////// �� �module.ProcessFeedback = function(feedbackname, feedbackstring) {
�� ��� �// put the feedback string in the buffer �� ��� �var text = feedbackstring.split("");�� ��� �� ��� �for ( var i = 0; i < text.length; i++ ) { �� ��� ��� �var digit = text[i].charCodeAt(0); �� ��� ��� �var hexy = digit.toString(16); �� ��� ��� �// ignore resync requests �� ��� ��� �if ( hexy === "f0" && i == 0) { return; } �� ��� ��� �if ( hexy === "ff" && i == 0) { return; } �� ��� ��� �module.buffer.push(hexy); �� ��� �}�� �� ��� �//module.log("Buffer " + module.buffer); �� ��� �// The first part of the buffer is the frame start �� ��� �// we want to get go the length marker and cut that chunk from the buffer and process it �� ��� �// find the first index of a frame start "64" �� ��� �var index = module.buffer.indexOf("64"); �� ��� �// remove everything that precedes it �� ��� �if ( index > 0 ) { �� ��� ��� �var waste = module.buffer.splice(0, index); �� ��� ��� �//module.log("Waste " + waste); �� ��� ��� �// reset the 64 index incase waste happened �� ��� ��� �index = module.buffer.indexOf("64"); �� ��� �} �� ��� �var framelength = 0; �� ��� �if ( module.buffer.length > 7 ) {�� ��� �� ��� ��� �framelength = parseInt(module.buffer[6], 16); �� ��� �//�� �module.log("Frame Length: " + framelength); �� ��� ��� �// if we have accumulated the whole frame in the buffer splice it out �� ��� ��� �var response = ""; �� ��� ��� �if ( index > -1 && module.buffer.length >= framelength + 3 ) { �� ��� ��� ��� �response = module.buffer.splice(0, framelength + 3);�� �� ��� ��� �//�� �module.log("\nResponse: " + response + "\n"); �� ��� ��� ��� �module.parseCommand(response); �� ��� ��� �}�� ��� ��� �� ��� �} �� ��� �//module.log("Buffer " + module.buffer ); �� ��� �� ��� �� ��� �� ��� �� ��� �� ��� �� ��� �/// OLD �� ��� �return; �� �� �� �� �� ��� �var text = feedbackstring.split(""); �� ��� �var hexstr = "fb>"; �� ��� �var hexstring = "HS"; �� ��� �for ( var i = 0; i < text.length; i++ ) { �� ��� ��� �var digit = text[i].charCodeAt(0); �� ��� ��� �var hexy = digit.toString(16); �� ��� ��� �if ( hexy === "f0" && i == 0) { return; } �� ��� ��� �if ( hexy === "ff" && i == 0) { return; } �� ��� ��� �module.buffer.push(hexy); �� ��� ��� �hexstring = hexstring + digit + " "; �� ��� ��� �hexstr = hexstr + hexy + " "; �� ��� �} �� ��� �module.log( "FEEDBACK " + hexstr ); �� ��� �� �� ��� �for ( var i = 0; i < module.buffer.length; i++ ) { �� ��� ��� �if ( module.buffer[i] === "8c" ) { �� ��� ��� ��� �// Ping �� ��� ��� ��� �module.log("Ping"); �� ��� ��� ��� �module.buffer.splice(i, 1); �� ��� ��� ��� �i--; �� ��� ��� �} else �� ��� ��� �if ( module.buffer[i] === "64" ) { �� ��� ��� �� ��� ��� ��� �// Command - Get Frame Count �� ��� ��� ��� �var framecount = ""; �� ��� ��� ��� �for ( var j = i+3; j < i + 7; j++ ) { �� ��� ��� ��� ��� �framecount +=� module.buffer[j]; �� ��� ��� ��� �} �� ��� ��� ��� �framecount = parseInt(framecount, 16); �� ��� ��� ��� �var cmd = module.buffer.splice(i, 1 + framecount + 2); �� ��� ��� ��� �i--; �� ��� ��� ��� �module.parseCommand( cmd ); �� ��� ��� �} else �� ��� ��� �if ( module.buffer[i] === "ff" ) { �� ��� ��� ��� �// Check for FF flush �� ��� ��� ��� �var ffcount = 0; �� ��� ��� ��� �var start = 0; �� ��� ��� ��� �for ( var j = i; j < module.buffer.length; j++ ) { �� ��� ��� ��� ��� �if ( module.buffer[j] === "ff" ) { �� ��� ��� ��� ��� ��� �if ( start == 0 ) { start = i; } �� ��� ��� ��� ��� ��� �ffcount++; �� ��� ��� ��� ��� �} �� ��� ��� ��� ��� �if ( module.buffer[j] !== "ff" ) { break; } �� ��� ��� ��� �} �� ��� ��� ��� �if ( ffcount > 4 ) { �� ��� ��� ��� �//�� �module.log("FF FLUSH"); �� ��� ��� ��� ��� �module.buffer.splice(i, ffcount); �� ��� ��� ��� ��� �i--; �� ��� ��� ��� ��� �return; �� ��� ��� ��� �} �� ��� ��� �} else �� ��� ��� �if ( module.buffer[i] === "f0" ) { �� ��� ��� ��� �// Check for FO flush �� ��� ��� ��� �var ffcount = 0; �� ��� ��� ��� �var start = 0; �� ��� ��� ��� �for ( var j = i; j < module.buffer.length; j++ ) { �� ��� ��� ��� ��� �if ( module.buffer[j] === "f0" ) { �� ��� ��� ��� ��� ��� �if ( start == 0 ) { start = i; } �� ��� ��� ��� ��� ��� �ffcount++; �� ��� ��� ��� ��� �} �� ��� ��� ��� ��� �if ( module.buffer[j] !== "f0" ) { break; } �� ��� ��� ��� �} �� ��� ��� ��� �if ( ffcount > 4 ) { �� ��� ��� ��� ��� �//module.log("F0 FLUSH"); �� ��� ��� ��� ��� �module.buffer.splice(i, ffcount); �� ��� ��� ��� ��� �i--; �� ��� ��� ��� ��� �return; �� ��� ��� ��� �} �� ��� ��� �} �� ��� �//�� �module.log( "FEEDBACK " + hexstr ); �� ��� ��� �if ( module.buffer.length > 0 ) { �� ��� ��� ��� �module.log("BUFFER> " + module.buffer); �� ��� ��� �} �� ��� �} �� �}; �� �/////////////////////////////// �� �// INTERNAL HELPER FUNCTIONS // �� �///////////////////////////////
�� �module.parseCommand = function(command) { �� �module.log("parse"); �� ��� �module.ack(); �� ��� �var framestart �� �= command.splice(0,1); �� ��� �var framecount� = command.splice(0,1); �� ��� �var version�� �= command.splice(0,1); �� ��� �var framelength�� �= command.splice(0,4); �� ��� �var src �� �= command.splice(0,6); �� ��� �var dest�� �= command.splice(0,6); �� ��� �var msgid�� �= command.splice(0,2); �� ��� �var flags�� �= command.splice(0,2); �� ��� �var payload�� �= command.splice(0,command.length-1); �� ��� �var checksum �� �= command.splice(0,1); �� ��� �var length �� �= "";�� �� ��� � �� ��� �for ( var i = 0; i < 4; i++ ) { �� ��� ��� �length +=� framelength[i]; �� ��� �} �� ��� �// DISCO MESSAGE �� ��� �if ( module.compareArrays(msgid, [0,0]) && module.compareArrays(flags,[0,4]) ) { �� ��� ��� �module.log("Disco Recieved"); �� ��� ��� �// if the disco ever fails the src[0] won't match, resubscribe �� ��� ��� �if ( module.disco[0] !== src[0] ) { �� ��� �� ��� ��� ��� �module.getVDList(); �� ��� ��� ��� �module.subscribe(module.zone1); �� ��� ��� ��� �module.subscribe(module.zone2); �� ��� ��� ��� �module.subscribe(module.zone3); �� ��� ��� ��� �module.subscribe(module.zone4);�� ��� ��� ��� �� ��� ��� ��� �� ��� ��� �}; �� ��� ��� �module.disco[0] = src[0]; �� ��� ��� �module.disco[1] = src[1]; �� ��� ��� �return; �� ��� �} �� ��� �// RTE/SV STATE INFORMATION �� ��� �if ( module.compareArrays(msgid, [1,0]) && module.compareArrays(flags,[8,0]) ) { �� ��� ��� �var foundzonejoin = 0; �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone1 )) { foundzonejoin = module.zone1join; } else �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone2 )) { foundzonejoin = module.zone2join; } else �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone3 )) { foundzonejoin = module.zone3join; } else �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone4 )) { foundzonejoin = module.zone4join; } else { module.log("Zone Not Found"); return; } �� ��� ��� ��� �� ��� ��� �// MUTE �� ��� ��� �if ( module.compareArrays([payload[0],payload[1],payload[2],payload[3]], [0,3,0,2] )) { �� ��� ��� ��� �//module.log("MUTE"); �� ��� ��� ��� �//module.log( "Trying to set Join d" + foundzonejoin + payload[3] + " to " + payload[5] );�� ��� ��� ��� ��� ��� ��� ��� �� ��� ��� ��� �CF.setJoin("d" + foundzonejoin + payload[3], payload[5]);�� ��� ��� ��� �� ��� ��� �} �� ��� ��� �// VOLUME �� ��� ��� �if ( module.compareArrays([payload[0],payload[1],payload[2],payload[3]], [0,3,0,1] )) { �� ��� ��� ��� �//module.log("VOLUME"); �� ��� ��� ��� �//module.log( "Trying to set Join a" + foundzonejoin + payload[3] + " to " + payload[6] );�� ��� ��� �� ��� ��� ��� �// convert volume to a decimal� 00 min DD max (0 - 221);�� ��� ��� ��� ��� ��� �� ��� ��� ��� �var volume = parseInt(payload[6], 16);�� ��� ��� �� ��� ��� ��� �var volinc = parseInt(65535 / 75); // 105 min 180 max (set for my house)� 75 = 180-105 �� ��� ��� ��� �var volset = (volume - 105) * volinc; �� ��� ��� ��� �CF.setJoin("a" + foundzonejoin + payload[3], volset );�� �� ��� ��� �} �� ��� ��� �// INPUT �� ��� ��� �if ( module.compareArrays([payload[0],payload[1],payload[2],payload[3]], [0,3,0,0] )) { �� ��� ��� ��� �//module.log("INPUT"); �� ��� ��� ��� �//module.log( "Trying to set Join d" + module.zone1join + payload[3] + payload[1] );�� ��� ��� ��� ��� ��� ��� ��� �� ��� ��� ��� �for (var i = 0; i <= 6; i++ ) { �� ��� ��� ��� ��� �CF.setJoin("d" + foundzonejoin + payload[3] + i, 0); �� ��� ��� ��� �}�� ��� ��� �� ��� ��� ��� �CF.setJoin("d" + foundzonejoin + payload[3] + payload[5], 1); �� ��� ��� �} �� ��� �} �� �//�� �if ( module.compareArrays( [src[2],src[3],src[4],src[5]], module.zone1 ) ) { �� ��� ��� �module.log( "Feedback: FS " + framestart + " FC " + framecount + " FL " + framelength + " SRC " + src + " DEST " + dest + " MSGID " + msgid + " FLAGS " + flags + " PAYLOAD " + payload + " CHK " + checksum ); �� �//�� �} �� ��� �� ��� �if ( module.compareArrays(msgid, [1,"1a"])� ) { �� ��� ��� �module.log("Get VD List Response " + payload); �� ��� ��� �module.describeVD(); �� ��� �} �� ��� �if ( module.compareArrays(msgid, [1,"1e"])� ) { �� ��� ��� �//module.log("Unkown Response"); �� ��� ��� �var numsv = payload.splice(0,2); �� ��� ��� �var sv_id = payload.splice(0,2); �� ��� ��� �var type� = payload.splice(0,1); �� ��� ��� �var sv_val = payload �� ��� ����� //�� module.log("NumSV " + numsv + " sv_id " + sv_id + " type " + type� + " svval " + sv_val ); �� ��� �} �� ��� �if ( module.compareArrays(msgid, [1,19])� ) { �� ��� ��� �module.log("Describe VD Response SRC " + src + " DEST " + dest ); �� ��� ��� �var numsv = payload.splice(0,2); �� ��� ��� �var sv_id = payload.splice(0,2); �� ��� ��� �var type� = payload.splice(0,1); �� ��� ��� �var sv_val = payload �� ��� �������� module.log("NumSV " + numsv + " sv_id " + sv_id + " type " + type� + " svval " + sv_val );�� ��� ��� �� ��� �}�� �� ��� �if ( module.compareArrays(msgid, [1,3]) ) { �� ��� ��� �var foundzonejoin = 0; �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone1 )) { foundzonejoin = module.zone1join; } else �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone2 )) { foundzonejoin = module.zone2join; } else �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone3 )) { foundzonejoin = module.zone3join; } else �� ��� ��� �if ( module.compareArrays([src[2],src[3],src[4],src[5]], module.zone4 )) { foundzonejoin = module.zone4join; } else { module.log("Zone Not Found"); return; }��
�� ��� ��� �//������������� 2�� INPUT 6���� VOLUME 11� MUTE� 15�� PAGE 19������� 23������� 27������� 31������� 35� PAGE VOL 40�������������� PAGE DUCKING������������������������������ 68����� PRVOL 73 PRTHRESH 77PRATTACK 81� PRHOLD 85PRRELEASE 89 PRDEPTH 93���������� RADIO �� ��� ��� �// PAYLOAD 0,18,[0,0,1,6],[0,1,3,0,9c],[0,2,1,1],[0,3,1,0],[0,4,1,0], [0,5,1,0],[0,6,1,0],[0,7,1,0],[0,8,3,0,b5],[0,9,1,28,0,a,1,9,0,b,1,0,0,c,1,12,0,d, 1,0,0,e,1,3,0,f,1,0],[0,10,3,0,b5],[0,11,1,28],[0,12,1,9],[0,13,1,0],[0,14,1,12], [0,15,1,0],[0,16,1,3],[0,17,1,0] �� ��� ��� �� ��� ��� �� ��� ��� �var input �� �= payload[5];� // �� ��� ��� �var vol �� �= payload[10]; // �� ��� ��� �var mute �� �= payload[14]; // �� ��� ��� �var page�� �= payload[18]; // �� ��� ��� �var pagevol�� �= payload[39]; // �� ��� ��� �var pgthreshold�� �= payload[43]; // �� ��� ��� �var pgattack�� �= payload[47]; // �� ��� ��� �var pghold�� �= payload[51]; // �� ��� ��� �var pgrelease�� �= payload[55]; //�� �� ��� ��� �var pgdepth�� �= payload[59]; // �� ��� ��� �var priority�� �= payload[67]; // �� ��� ��� �var priorityvol = payload[72]; // �� ��� ��� �var prthreshold�� �= payload[76]; // �� ��� ��� �var prattack�� �= payload[80]; // �� ��� ��� �var prhold�� �= payload[84]; // �� ��� ��� �var prrelease�� �= payload[88]; // �� ��� ��� �var prdepth�� �= payload[92]; // �� ��� ��� �var masterradio = payload[100];// �� ��� ��� �// set mute button �� ��� ��� �CF.setJoin("d" + foundzonejoin + payload[12], mute); �� ��� ��� �� ��� ��� �// set input buttons �� ��� ��� �for (var i = 0; i <= 6; i++ ) { �� ��� ��� ��� �CF.setJoin("d" + foundzonejoin + payload[3] + i, 0); �� ��� ��� �}�� ��� �� ��� ��� �CF.setJoin("d" + foundzonejoin + 0 + payload[5], 1);�� ��� ��� �� ��� ��� �� ��� ��� �// set volume sliders�� ��� ��� �� ��� ��� �var volume = parseInt(vol, 16);�� ��� ��� �� ��� ��� �var volinc = parseInt(65535 / 75); // 105 min 180 max (set for my house)� 75 = 180-105 �� ��� ��� �var volset = (volume - 105) * volinc;�� ��� �� ��� ��� �CF.setJoin("a" + foundzonejoin + 1, volset );�� ��� ��� ��� ��� �� ��� �} �� ��� �payload = payload.splice(41,27); �� ��� �return; �� �}; �� �module.resync = function() { �� ��� �module.log("resync"); �� ��� �var resyncrequest = []; �� ��� �for ( var i = 0; i < 16; i++ ) { �� ��� ��� �resyncrequest.push("FF"); �� ��� �}; �� ��� �module.sendCommand(resyncrequest); �� ��� �var resyncack = []; �� ��� �for ( var i = 0; i < 261; i++ ) { �� ��� ��� �resyncack.push("F0"); �� ��� �} �� ��� �module.sendCommand(resyncack, "resync", 1); �� �}; �� �module.ack = function() { �� ��� �module.sendCommand(["A5"], "ack", 0); �� �}; �� �� �module.compareArrays = function( array1, array2 ) { �� ��� �var equal = 1; �� ��� �//module.log( "COMPARE " + array1 +� " " + array2 ); �� ��� �if (array1.length != array2.length ) { equal = 0; } �� ��� �for ( var i = 0; i < array1.length; i++ ) { �� ��� ��� �if ( parseInt(array1[i],16) != parseInt(array2[i],16) ) {� equal = 0; } �� ��� �} �� ��� �return equal; �� �}; �� �module.sendHeartbeat = function() { �� ��� �// ever second �� ��� �// Heartbeat F0 8C �� ��� �module.sendCommand(["F0","8C"], "ping", 0); �� �}; �� �module.hexify = function( array ) { �� ��� �var string = ""; �� ��� �var tstring = ""; �� ��� �for ( var i = 0; i < array.length; i++) { �� ��� ��� �string = string + String.fromCharCode(parseInt(array[i],16)); �� ��� ��� �tstring = tstring + " " + parseInt(array[i],16); �� ��� ��� �� ��� �} �� �//�� �module.log(tstring); �� ��� �return string; �� �}; ������� module.checksum = function(dbx) { ��������������� var ccit = ["5E","BC","E2","61","3F","DD","83","C2","9C","7E","20","A3","FD","1F","41","9D","C3","21","7F","FC","A2","40","1E","5F","01","E3","BD","3E","60","82","DC","23", "7D","9F","C1","42","1C","FE","A0","E1","BF","5D","03","80","DE","3C","62","BE"," E0","02","5C","DF","81","63","3D","7C","22","C0","9E","1D","43","A1","FF","46"," 18","FA","A4","27","79","9B","C5","84","DA","38","66","E5","BB","59","07","DB"," 85","67","39","BA","E4","06","58","19","47","A5","FB","78","26","C4","9A","65"," 3B","D9","87","04","5A","B8","E6","A7","F9","1B","45","C6","98","7A","24","F8"," A6","44","1A","99","C7","25","7B","3A","64","86","D8","5B","05","E7","B9","8C"," D2","30","6E","ED","B3","51","0F","4E","10","F2","AC","2F","71","93","CD","11"," 4F","AD","F3","70","2E","CC","92","D3","8D","6F","31","B2","EC","0E","50","AF"," F1","13","4D","CE","90","72","2C","6D","33","D1","8F","0C","52","B0","EE","32"," 6C","8E","D0","53","0D","EF","B1","F0","AE","4C","12","91","CF","2D","73","CA"," 94","76","28","AB","F5","17","49","08","56","B4","EA","69","37","D5","8B","57"," 09","EB","B5","36","68","8A","D4","95","CB","29","77","F4","AA","48","16","E9"," B7","55","0B","88","D6","34","6A","2B","75","97","C9","4A","14","F6","A8","74"," 2A","C8","96","15","4B","A9","F7","B6","E8","0A","54","D7","89","6B","35"]; ��������������� var bcc = "FF"; ��������������� for (var i = 1; i < dbx.length; i++ ) { ������������������� var dbx1 = parseInt(dbx[i],16); ������������������� var bcc1 = parseInt(bcc,16); ������������������ var bcc = ccit[(bcc1^dbx1)-1]; ��������������� } ��������������� return bcc; ������� }; �� �module.sendCommand = function (command, descrip, debug) { �� ��� �if (debug) { module.log("send command: " + descrip + " " + command); } �� ��� �command = module.hexify(command); �� �//�� �module.log("sent command: " + command); �� ��� �CF.send("Moxa_ZonePro", command); �� �}; �� �// Only allow logging calls when CF is in debug mode - better performance in release mode this way �� �module.log = function(msg) { �� ��� �if (CF.debug && module.debug) { �� ��� ��� �CF.log("ZonePro: " + msg); �� ��� �} �� �}; �� �� �� �� �� �return module; }; CF.modules.push({ �� �name: "ZonePro", �� �object: ZonePro, �� �version: 1.0 });
Last edited by Fiasco on March 24, 2024 02:07.
|
Pump House on Facebook: [Link: facebook.com] |
|
| OP | Post 6 made on March 21, 2024 at 18:09 |
|
Joined: Posts: | July 2009 1,285 |
|
|
try { �� ��� �ZonePro = new ZonePro(); �� ��� �// system name, system feedback, node address �� ��� �ZonePro.setup( "Moxa_ZonePro", "Moxa_ZonePro_Feedback", 138, 0 ); // get these addresses by highlighting the RTE in zone pro designer and hitting ctrl+shift+0 �� ��� �ZonePro.setupRTE(1, [20, 00, 05, 01]); �� ��� �ZonePro.setupRTE(2, [21, 01, 05, 01]); �� ��� �ZonePro.setupRTE(3, [22, 02, 05, 01]); �� ��� �ZonePro.setupRTE(4, [23, 03, 05, 01]); �� ��� �� �� �} catch ( err ) { �� ��� �CF.log("ZonePro Setup Error " + err.message ); �� �} �� ���� ZonePro.initialize();
|
Pump House on Facebook: [Link: facebook.com] |
|
| OP | Post 7 made on March 24, 2024 at 02:06 |
|
Joined: Posts: | July 2009 1,285 |
|
|
Got the RTE's done, adding the RTE EQ functions w/ feedback now. That's about all I really need to pull to control the audio from a remote interface. The input/output live meter levels are completely undocumented so I'm going to try to figure those out next.

|
Pump House on Facebook: [Link: facebook.com] |
|
| OP | Post 8 made on March 27, 2024 at 17:12 |
|
Joined: Posts: | July 2009 1,285 |
|
|
Got control of 100% of the ZonePro's functions now with feedback.�� Now I'm just refining the code to make it more efficient and portable. Reworked my EQ meter artwork as well. I don't have a 1200 series to test against, just my home 640 and the bar 640. 



|
Pump House on Facebook: [Link: facebook.com] |
|
 |
Before you can reply to a message... |
You must first register for a Remote Central user account - it's fast and free! Or, if you already have an account, please login now. |
Please read the following: Unsolicited commercial advertisements are absolutely not permitted on this forum. Other private buy & sell messages should be posted to our Marketplace. For information on how to advertise your service or product click here. Remote Central reserves the right to remove or modify any post that is deemed inappropriate.
|