Help controlling Crown amps
I have several Crown CTs series amps, all of which have PIP-Lite Module cards on them. I need to control the listen bus - select which channel to listen to (1 or 2), and the enable / disable (mute / unmute) state, and I need to do this over IP.
If anyone has a code block / sample of a job they've done this on, or even the protocol manual, I would be very appreciative. I downloaded the following from Crown's website. They show the IP port and command structure, but I don't see a listing of actual commands in any of them:
136763.pdf
TCP-IQ Network Control Protocol.pdf
UDP_IQ_Network_Control_Protocol.pdf
I also have a file called "UDPDevelopersKit.uue" that is 1,317KB, but no idea how to open a .uue file.
Again, thanks for any help y'all can give me.
If anyone has a code block / sample of a job they've done this on, or even the protocol manual, I would be very appreciative. I downloaded the following from Crown's website. They show the IP port and command structure, but I don't see a listing of actual commands in any of them:
136763.pdf
TCP-IQ Network Control Protocol.pdf
UDP_IQ_Network_Control_Protocol.pdf
I also have a file called "UDPDevelopersKit.uue" that is 1,317KB, but no idea how to open a .uue file.
Again, thanks for any help y'all can give me.
Comments
I have uploaded what information I have on this. I looked at doing some of this a few years back but never did anything with it. At that time I had gotten an email address from the folks at crown (probably from someone in engineering there) for a guy in Germany that had some Amx control of PIP cards working but never emailed him and seem to have lost his info. You might try calling crown and make a few inquiries about this. If you get nowhere with them, message me back and I'll ask my boss who we got that email address from. He knows a few people at crown.
If you get something working and are interested in sharing it, I'd be interested.
Good luck,
Jeff Beam
I e-mailed Crown tech support and he sent me some .oif files for the PIP Lites. (The oif files are viewed using the OIF Utility that gets installed when you use the exe in the zip that jbeam attached). It turns out that I didn't exactly "need" the oif file though, as I was able to get the same information using BSS London Architect. I included the PIP Lite oif zip file I got from Crown anyway in case anyone wants it.
When using London Architect, you have to be on the same subnet as the devices you are looking for, at least I couldn't find a way to find it while on a different subnet. The devices were on x.x.6.x and I was on x.x.5.x and couldn't see them through Architect until I moved to the .6. subnet. I could ping them though. Once you're on the same subnet and you have Architect open, click on the network refresh button in the bottom left window if you don't already see "unused" devices in your network tree. Once the pip cards come up, drag them into your project (you don't have to save the project) and click on the PIP object. Then in the bottom window, network properties, you should see the PIP Lite card's HiQnet address and IP address. In the left window, click on the properties tab and you can see the property list, of which I needed Listen Bus channel select (500) and Listen Bus enable (501). I also got the 500 and 501 from the oif utility with the PIP Lite oif file, but the oif didn't show me the HiQnet address or IP address.
Some of the info I got in the response from Crown is that the message size byte (22 in my case) is constant, and for each parameter, if it says 16 bytes but the manual only shows you one byte, you have to put in leading zeroes, so $01 becomes $00, $01; if the manual says the data is 32 bytes but only shows one byte, again with the leading zeroes, so $01 becomes $00, $00, $00, $01. So, overall, the manual was not incorrect, it just didn't go into much detail.
Anyway, here is the code I wrote:
Notes:
EDIT: my logic in the button events was to make all channels on all amps mutually exclusive so that you could only be listening to one listen bus channel on one amp at a time. /EDIT
PAx-xx = object name in London Architect file
In the command string, the byte count is hex ($16) which is decimal 22; the Source IQ address of $FF, $FE seem to be always $FF, $FE
For the feedback, I had a button whose off state is green (to reflect enabled) and on state is red (to reflect disabled), that is why the feedback reads "If the bus is not enabled, or (if the bus is enabled and) the channel being listened to is x". I know I could have changed it, that would probably be less confusing, before getting this iteration I was calling the bus enable "mute" hence the red for on state, but I had the buttons made and thought it would be easier to adapt my code than to change 40 buttons haha.
DEFINE_DEVICE dvC1 = 0:11:0 // IP control - Crown PIP Lite card - 169.254.1.201 PA3-01 dvC2 = 0:12:0 // IP control - Crown PIP Lite card - 169.254.1.202 PA3-02 dvC3 = 0:13:0 // IP control - Crown PIP Lite card - 169.254.1.203 PA2-01 dvC4 = 0:14:0 // IP control - Crown PIP Lite card - 169.254.1.204 PA2-02 dvC5 = 0:15:0 // IP control - Crown PIP Lite card - 169.254.1.205 PA2-03 dvC6 = 0:16:0 // IP control - Crown PIP Lite card - 169.254.1.206 PA2-04 dvC7 = 0:17:0 // IP control - Crown PIP Lite card - 169.254.1.207 PA2-05 dvC8 = 0:18:0 // IP control - Crown PIP Lite card - 169.254.1.208 PA3-03 dvC9 = 0:19:0 // IP control - Crown PIP Lite card - 169.254.1.209 PA3-04 dvC10 = 0:20:0 // IP control - Crown PIP Lite card - 169.254.1.210 PA2-09 dvC11 = 0:21:0 // IP control - Crown PIP Lite card - 169.254.1.211 PA3-06 dvC12 = 0:22:0 // IP control - Crown PIP Lite card - 169.254.1.212 PA3-07 dvC13 = 0:23:0 // IP control - Crown PIP Lite card - 169.254.1.213 PA3-08 dvC14 = 0:24:0 // IP control - Crown PIP Lite card - 169.254.1.214 PA3-09 dvC15 = 0:25:0 // IP control - Crown PIP Lite card - 169.254.1.215 PA3-10 dvC16 = 0:26:0 // IP control - Crown PIP Lite card - 169.254.1.216 PA2-06 dvC17 = 0:27:0 // IP control - Crown PIP Lite card - 169.254.1.217 PA2-07 dvC18 = 0:28:0 // IP control - Crown PIP Lite card - 169.254.1.218 PA2-08 dvC19 = 0:29:0 // IP control - Crown PIP Lite card - 169.254.1.219 PA3-05 DEFINE_CONSTANT dev dvAmp[19] = { dvC1, dvC2, dvC3, dvC4, dvC5, dvC6, dvC7, dvC8, dvC9, dvC10,dvC11,dvC12,dvC13,dvC14,dvC15,dvC16,dvC17,dvC18,dvC19 } char nAmpIQ[19][2] = { {$25,$A4}, // PA3-01 169.254.1.201 {$70,$C1}, // PA3-02 .202 {$8A,$74}, // PA2-01 .203 {$06,$89}, // PA2-02 .204 {$73,$0F}, // PA2-03 .205 {$33,$C1}, // PA2-04 .206 {$35,$43}, // PA2-05 .207 {$1A,$F8}, // PA3-03 .208 {$6D,$FC}, // PA3-04 .209 {$14,$3B}, // PA2-09 .210 {$1C,$DE}, // PA3-06 .211 {$02,$84}, // PA3-07 .212 {$3B,$1A}, // PA3-08 .213 {$83,$B7}, // PA3-09 .214 {$77,$D5}, // PA3-10 .215 {$17,$B8}, // PA2-06 .216 {$54,$C7}, // PA2-07 .217 {$3E,$2E}, // PA2-08 .218 {$0D,$7C} // PA3-05 .219 } char nChanSel[2] = {$01,$F4} // Object ID for Listen Bus Channel Select (500) char nMuteID[2] = {$01,$F5} // Object ID of the Listen Bus Mute Enable (501) integer nC1ReconTL = 11 integer nC2ReconTL = 12 integer nC3ReconTL = 13 integer nC4ReconTL = 14 integer nC5ReconTL = 15 integer nC6ReconTL = 16 integer nC7ReconTL = 17 integer nC8ReconTL = 18 integer nC9ReconTL = 19 integer nC10ReconTL = 20 integer nC11ReconTL = 21 integer nC12ReconTL = 22 integer nC13ReconTL = 23 integer nC14ReconTL = 24 integer nC15ReconTL = 25 integer nC16ReconTL = 26 integer nC17ReconTL = 27 integer nC18ReconTL = 28 integer nC19ReconTL = 29 integer nCrownPort = 5600 char sC1IP[] = '169.254.1.201' char sC2IP[] = '169.254.1.202' char sC3IP[] = '169.254.1.203' char sC4IP[] = '169.254.1.204' char sC5IP[] = '169.254.1.205' char sC6IP[] = '169.254.1.206' char sC7IP[] = '169.254.1.207' char sC8IP[] = '169.254.1.208' char sC9IP[] = '169.254.1.209' char sC10IP[] = '169.254.1.210' char sC11IP[] = '169.254.1.211' char sC12IP[] = '169.254.1.212' char sC13IP[] = '169.254.1.213' char sC14IP[] = '169.254.1.214' char sC15IP[] = '169.254.1.215' char sC16IP[] = '169.254.1.216' char sC17IP[] = '169.254.1.217' char sC18IP[] = '169.254.1.218' char sC19IP[] = '169.254.1.219' DEFINE_VARIABLE char sConnectError[20][255] volatile integer bBusEnable[19] = // Enable state for the listen bus on 19 amps { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } volatile integer nAmpChan[19] // Which listen bus channel is being sent volatile integer nPrevAmp volatile integer nCurrAmp volatile integer nCurrChan DEFINE_START sConnectError[6] = "'The device has refused the connection request on port '" sConnectError[7] = "'The connection attempt has timed out - the device is likely off the network'" sConnectError[8] = "'The connection attempt has failed with an unknown error'" timeline_create (nC1ReconTL, lReconnectTLTime, 11, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC2ReconTL, lReconnectTLTime, 12, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC3ReconTL, lReconnectTLTime, 13, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC4ReconTL, lReconnectTLTime, 14, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC5ReconTL, lReconnectTLTime, 15, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC6ReconTL, lReconnectTLTime, 16, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC7ReconTL, lReconnectTLTime, 17, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC8ReconTL, lReconnectTLTime, 18, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC9ReconTL, lReconnectTLTime, 19, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC10ReconTL, lReconnectTLTime, 20, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC11ReconTL, lReconnectTLTime, 21, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC12ReconTL, lReconnectTLTime, 22, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC13ReconTL, lReconnectTLTime, 23, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC14ReconTL, lReconnectTLTime, 24, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC15ReconTL, lReconnectTLTime, 25, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC16ReconTL, lReconnectTLTime, 26, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC17ReconTL, lReconnectTLTime, 27, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC18ReconTL, lReconnectTLTime, 28, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) timeline_create (nC19ReconTL, lReconnectTLTime, 29, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) ip_client_open (dvC1.port, sC1IP, nCrownPort, TCP) ip_client_open (dvC2.port, sC2IP, nCrownPort, TCP) ip_client_open (dvC3.port, sC3IP, nCrownPort, TCP) ip_client_open (dvC4.port, sC4IP, nCrownPort, TCP) ip_client_open (dvC5.port, sC5IP, nCrownPort, TCP) ip_client_open (dvC6.port, sC6IP, nCrownPort, TCP) ip_client_open (dvC7.port, sC7IP, nCrownPort, TCP) ip_client_open (dvC8.port, sC8IP, nCrownPort, TCP) ip_client_open (dvC9.port, sC9IP, nCrownPort, TCP) ip_client_open (dvC10.port, sC10IP, nCrownPort, TCP) ip_client_open (dvC11.port, sC11IP, nCrownPort, TCP) ip_client_open (dvC12.port, sC12IP, nCrownPort, TCP) ip_client_open (dvC13.port, sC13IP, nCrownPort, TCP) ip_client_open (dvC14.port, sC14IP, nCrownPort, TCP) ip_client_open (dvC15.port, sC15IP, nCrownPort, TCP) ip_client_open (dvC16.port, sC16IP, nCrownPort, TCP) ip_client_open (dvC17.port, sC17IP, nCrownPort, TCP) ip_client_open (dvC18.port, sC18IP, nCrownPort, TCP) ip_client_open (dvC19.port, sC19IP, nCrownPort, TCP) DEFINE_EVENT data_event[dvC1] { string : { send_string 0, "'Data from Crown1: ',data.text" } online : { if (timeline_active (nC1ReconTL)) { timeline_kill(nC1ReconTL) } send_string 0, "'Crown1 connected via IP, stopping timeline'" } offline: { if (!timeline_active (nC1ReconTL)) { timeline_create (nC1ReconTL, lReconnectTLTime, 1, TIMELINE_ABSOLUTE, TIMELINE_REPEAT) } ip_client_open (dvC1.port, sC1IP, nCrownPort, TCP) send_string 0, "'Crown1 disconnected, reconnecting and starting reconnect timeline'" } onerror: { stack_var char sMsg[255] send_string 0, "'Crown1 connection error with code ',itoa(data.number),':'" sMsg = sConnectError[data.number] if (data.number == 6) { sMsg = "sMsg, itoa(nCrownPort)" } send_string 0, "' "',sMsg,'"'" send_string 0, "'Trying again in 30 seconds'" } } timeline_event[nC1ReconTL] { send_string 0, "'Crown1 connection attempt'" ip_client_open (dvC1.port, sC1IP, nCrownPort, TCP) } // REPEAT FOR EVERY AMP, OR COMBINE THEM ALL INTO THE ONE EVENT // Listen Bus muting button_event[dvTP1b, 41] // Amp 1 Ch 1 button_event[dvTP1b, 42] // Amp 2 button_event[dvTP1b, 43] // Amp 3 button_event[dvTP1b, 44] // Amp 4 button_event[dvTP1b, 45] // Amp 5 button_event[dvTP1b, 46] // Amp 6 button_event[dvTP1b, 47] // Amp 7 button_event[dvTP1b, 48] // Amp 8 button_event[dvTP1b, 49] // Amp 9 button_event[dvTP1b, 50] // Amp 10 button_event[dvTP1b, 51] // Amp 11 button_event[dvTP1b, 52] // Amp 12 button_event[dvTP1b, 53] // Amp 13 button_event[dvTP1b, 54] // Amp 14 button_event[dvTP1b, 55] // Amp 15 button_event[dvTP1b, 56] // Amp 16 button_event[dvTP1b, 57] // Amp 17 button_event[dvTP1b, 58] // Amp 18 button_event[dvTP1b, 59] // Amp 19 button_event[dvTP1b, 61] // Amp 1 Ch 2 button_event[dvTP1b, 62] // Amp 2 button_event[dvTP1b, 63] // Amp 3 button_event[dvTP1b, 64] // Amp 4 button_event[dvTP1b, 65] // Amp 5 button_event[dvTP1b, 66] // Amp 6 button_event[dvTP1b, 67] // Amp 7 button_event[dvTP1b, 68] // Amp 8 button_event[dvTP1b, 69] // Amp 9 button_event[dvTP1b, 70] // Amp 10 button_event[dvTP1b, 71] // Amp 11 button_event[dvTP1b, 72] // Amp 12 button_event[dvTP1b, 73] // Amp 13 button_event[dvTP1b, 74] // Amp 14 button_event[dvTP1b, 75] // Amp 15 button_event[dvTP1b, 76] // Amp 16 button_event[dvTP1b, 77] // Amp 17 button_event[dvTP1b, 78] // Amp 18 button_event[dvTP1b, 79] // Amp 19 { push: { // Store the last amp manipulated nPrevAmp = nCurrAmp // Store the amp and channel to be manipulated if (button.input.channel < 60) // buttons 41 - 59 { nCurrAmp = button.input.channel - 40 // 1 - 19 nCurrChan = 0 // Channel 1 } else // buttons 61 - 79 { nCurrAmp = button.input.channel - 60 // 1 - 19 nCurrChan = 1 // Channel 2 } // Check the current amp against the previous amp // If they are the same if (nPrevAmp == nCurrAmp) { // Check the previous channel against the current channel // If the desired channel is not selected if (nAmpChan[nCurrAmp] != nCurrChan) { // Select the desired channel nAmpChan[nCurrAmp] = nCurrChan send_string dvAmp[nCurrAmp], "'IQ',$00,$00,$00,$16,$00,$06,$01,$00,$FF,$FE,$00,$00,nAmpIQ[nCurrAmp],$00,$01,nChanSel,$01,nCurrChan" // If the listen bus is not enabled (muted) if (!bBusEnable[nCurrAmp]) { // enable it (unmute) bBusEnable[nCurrAmp] = 1 send_string dvAmp[nCurrAmp], "'IQ',$00,$00,$00,$16,$00,$06,$01,$00,$FF,$FE,$00,$00,nAmpIQ[nCurrAmp],$00,$01,nMuteID,$01,$01" } } // If the desired channel and selected channel match else { // toggle the listen bus enabled state (mute) bBusEnable[nCurrAmp] = !bBusEnable[nCurrAmp] send_string dvAmp[nCurrAmp], "'IQ',$00,$00,$00,$16,$00,$06,$01,$00,$FF,$FE,$00,$00,nAmpIQ[nCurrAmp],$00,$01,nMuteID,$01,bBusEnable[nCurrAmp]" } } // If the two amps are different else if (nPrevAmp != nCurrAmp) { // don't try to send to a nonexistant amp if (nPrevAmp) { // disable the listen bus on the previous amp (mute) bBusEnable[nPrevAmp] = 0 send_string dvAmp[nPrevAmp], "'IQ',$00,$00,$00,$16,$00,$06,$01,$00,$FF,$FE,$00,$00,nAmpIQ[nPrevAmp],$00,$01,nMuteID,$01,$00" } // If the desired channel is not already selected on this amp if (nAmpChan[nCurrAmp] != nCurrChan) { // select the desired channel nAmpChan[nCurrAmp] = nCurrChan send_string dvAmp[nCurrAmp], "'IQ',$00,$00,$00,$16,$00,$06,$01,$00,$FF,$FE,$00,$00,nAmpIQ[nCurrAmp],$00,$01,nChanSel,$01,nCurrChan" } // enable the listen bus on the current amp (unmute) bBusEnable[nCurrAmp] = 1 send_string dvAmp[nCurrAmp], "'IQ',$00,$00,$00,$16,$00,$06,$01,$00,$FF,$FE,$00,$00,nAmpIQ[nCurrAmp],$00,$01,nMuteID,$01,$01" } } } DEFINE_PROGRAM // Listen bus muting [dvTP1b, 41] = (!bBusEnable[1] || (nAmpChan[1] == 1)) // Amp 1 Ch 1 [dvTP1b, 42] = (!bBusEnable[2] || (nAmpChan[2] == 1)) // Amp 2 Ch 1 [dvTP1b, 43] = (!bBusEnable[3] || (nAmpChan[3] == 1)) // Amp 3 Ch 1 [dvTP1b, 44] = (!bBusEnable[4] || (nAmpChan[4] == 1)) // Amp 4 Ch 1 [dvTP1b, 45] = (!bBusEnable[5] || (nAmpChan[5] == 1)) // Amp 5 Ch 1 [dvTP1b, 46] = (!bBusEnable[6] || (nAmpChan[6] == 1)) // Amp 6 Ch 1 [dvTP1b, 47] = (!bBusEnable[7] || (nAmpChan[7] == 1)) // Amp 7 Ch 1 [dvTP1b, 48] = (!bBusEnable[8] || (nAmpChan[8] == 1)) // Amp 8 Ch 1 [dvTP1b, 49] = (!bBusEnable[9] || (nAmpChan[9] == 1)) // Amp 9 Ch 1 [dvTP1b, 50] = (!bBusEnable[10] || (nAmpChan[10] == 1)) // Amp 10 Ch 1 [dvTP1b, 51] = (!bBusEnable[11] || (nAmpChan[11] == 1)) // Amp 11 Ch 1 [dvTP1b, 52] = (!bBusEnable[12] || (nAmpChan[12] == 1)) // Amp 12 Ch 1 [dvTP1b, 53] = (!bBusEnable[13] || (nAmpChan[13] == 1)) // Amp 13 Ch 1 [dvTP1b, 54] = (!bBusEnable[14] || (nAmpChan[14] == 1)) // Amp 14 Ch 1 [dvTP1b, 55] = (!bBusEnable[15] || (nAmpChan[15] == 1)) // Amp 15 Ch 1 [dvTP1b, 56] = (!bBusEnable[16] || (nAmpChan[16] == 1)) // Amp 16 Ch 1 [dvTP1b, 57] = (!bBusEnable[17] || (nAmpChan[17] == 1)) // Amp 17 Ch 1 [dvTP1b, 58] = (!bBusEnable[18] || (nAmpChan[18] == 1)) // Amp 18 Ch 1 [dvTP1b, 59] = (!bBusEnable[19] || (nAmpChan[19] == 1)) // Amp 19 Ch 1 [dvTP1b, 61] = (!bBusEnable[1] || (nAmpChan[1] == 0)) // Amp 1 Ch 2 [dvTP1b, 62] = (!bBusEnable[2] || (nAmpChan[2] == 0)) // Amp 2 Ch 2 [dvTP1b, 63] = (!bBusEnable[3] || (nAmpChan[3] == 0)) // Amp 3 Ch 2 [dvTP1b, 64] = (!bBusEnable[4] || (nAmpChan[4] == 0)) // Amp 4 Ch 2 [dvTP1b, 65] = (!bBusEnable[5] || (nAmpChan[5] == 0)) // Amp 5 Ch 2 [dvTP1b, 66] = (!bBusEnable[6] || (nAmpChan[6] == 0)) // Amp 6 Ch 2 [dvTP1b, 67] = (!bBusEnable[7] || (nAmpChan[7] == 0)) // Amp 7 Ch 2 [dvTP1b, 68] = (!bBusEnable[8] || (nAmpChan[8] == 0)) // Amp 8 Ch 2 [dvTP1b, 69] = (!bBusEnable[9] || (nAmpChan[9] == 0)) // Amp 9 Ch 2 [dvTP1b, 70] = (!bBusEnable[10] || (nAmpChan[10] == 0)) // Amp 10 Ch 2 [dvTP1b, 71] = (!bBusEnable[11] || (nAmpChan[11] == 0)) // Amp 11 Ch 2 [dvTP1b, 72] = (!bBusEnable[12] || (nAmpChan[12] == 0)) // Amp 12 Ch 2 [dvTP1b, 73] = (!bBusEnable[13] || (nAmpChan[13] == 0)) // Amp 13 Ch 2 [dvTP1b, 74] = (!bBusEnable[14] || (nAmpChan[14] == 0)) // Amp 14 Ch 2 [dvTP1b, 75] = (!bBusEnable[15] || (nAmpChan[15] == 0)) // Amp 15 Ch 2 [dvTP1b, 76] = (!bBusEnable[16] || (nAmpChan[16] == 0)) // Amp 16 Ch 2 [dvTP1b, 77] = (!bBusEnable[17] || (nAmpChan[17] == 0)) // Amp 17 Ch 2 [dvTP1b, 78] = (!bBusEnable[18] || (nAmpChan[18] == 0)) // Amp 18 Ch 2 [dvTP1b, 79] = (!bBusEnable[19] || (nAmpChan[19] == 0)) // Amp 19 Ch 2