SSH Connection to a Biamp TesiraForte AI mixer
I spent a bunch of time writing the code necessary to talk to our first Biamp mixer. This was also my first foray into SSH connections. Please feel free to use my code; it is a thank you for all of the valuable information I have gleaned from this forum.
1
Comments
DEFINE_DEVICE
dvMIXER_IP = 0:4:0 //BIAMP TESIRAFORTE AI MIXER
DEFINE_VARIABLE
NON_VOLATILE CHAR sMixerBuffer[256]; //ARRAY TO STORE TEXT FROM THE MIXER
VOLATILE INTEGER nMixer_Connected //Variable to track state of SSH connection between master and mixer
//MIXER FUNCTIONS
DEFINE_FUNCTION fnMIXER_SSH_CLIENT_OPEN()
{
SSH_CLIENT_OPEN(4, '172.28.115.131', 22, 'admin', 'KAR309biAmp', '/ certs/id_rsa', '') //OPEN A SECURE SHELL CONSOLE SESSION WITH THE MIXER. I am leaving the privateKeyPathname and privateKeyPassphrase empty, as I am sending the password and have not created a private key.
}
DEFINE_FUNCTION fnMIXER_SSH_CLIENT_CLOSE()
{
SSH_CLIENT_CLOSE(4) //CLOSE THE SECURE SHELL CONSOLE SESSION WITH THE MIXER
}
//Here is an example of one of my mixer functions to show the syntax that works for me.
//The contents of the string literal will vary depending on the programming inside the mixer, but the hex line feed is appropriate.
DEFINE_FUNCTION fnMIC_MUTE_ON() //MIC MUTE ON
{
SEND_STRING dvMIXER_IP, "'Input1 set mute 1 true',$0A" //MUTE INPUT 1
}
//When the user launches an Audio-Only or Audio-Visual Presentation, that code section includes...
fnMIXER_SSH_CLIENT_OPEN(); //ESTABLISH COMMUNICATION WITH THE MIXER
WAIT_UNTIL (nMixer_Connected == 1) //Wait until a SSH connection has been established between the master and the mixer.
{
//Mute inputs, set default volume levels, etc.
}
//When the user is finished and chooses System Shutdown, that code section includes...
//I send several strings to place the mixer in my preferred default state, then I wait four seconds for the strings to soak in, then I close the SSH connection.
WAIT 40 //WAIT 4 SECONDS FROM PUSH
{
fnMIXER_SSH_CLIENT_CLOSE() //STOP COMMUNICATION WITH THE MIXER
}
and
DEFINE_START
//MIXER BUFFER
CREATE_BUFFER dvMIXER_IP, sMixerBuffer; //CREATES A LINK BETWEEN MIXER STRING EVENTS AND THE VARIABLE
and
I will post the data event in two chunks, or complete, once I figure out how to post a large code snippet.
DATA_EVENT [dvMIXER_IP] //Biamp TesiraForte AI
{
ONLINE:
{
nMixer_Connected = 1 //Set the variable to track state of SSH connection between master and mixer
}
OFFLINE:
{
nMixer_Connected = 0 //Set the variable to track state of SSH connection between master and mixer
}
STRING: //DURING NEGOTIATION OF THE SSH CONNECTION, WE WANT TO REFUSE ALL OPTIONS, RESULTING IN A RAW CONNECTION
{
IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$18',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO TERMINAL TYPE)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$18',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$18',$0A"; //SEND A RESPONSE...(WON'T TERMINAL TYPE)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$20',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO TERMINAL SPEED)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$20',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$20',$0A"; //SEND A RESPONSE...(WON'T TERMINAL SPEED)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$23',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DISPLAY LOCATION)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$23',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$23',$0A"; //SEND A RESPONSE...(WON'T DISPLAY LOCATION)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$27',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO NEW ENVIRONMENT OPTION)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$27',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$27',$0A"; //SEND A RESPONSE...(WON'T NEW ENVIRONMENT OPTION)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$24',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO ENVIRONMENT OPTION)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$24',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$24',$0A"; //SEND A RESPONSE...(WON'T ENVIRONMENT OPTION)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FB,$03',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(WILL SUPPRESS GO AHEAD)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FB,$03',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FE,$03',$0A"; //SEND A RESPONSE...(DON'T SUPPRESS GO AHEAD)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$01',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO ECHO)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$01',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$01',$0A"; //SEND A RESPONSE...(WON'T ECHO)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$22',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO LINEMODE)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$22',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$22',$0A"; //SEND A RESPONSE...(WON'T LINEMODE)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$1F',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO NEGOTIATE ABOUT WINDOW SIZE)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$1F',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$1F',$0A"; //SEND A RESPONSE...(WON'T NEGOTIATE ABOUT WINDOW SIZE)
}
continued...
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FB,$05',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(WILL STATUS)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FB,$05',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FE,$05',$0A"; //SEND A RESPONSE...(DON'T STATUS)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$21',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO REMOTE FLOW CONTROL)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$21',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$21',$0A"; //SEND A RESPONSE...(WON'T REMOTE FLOW CONTROL)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FB,$01',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(WILL ECHO)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FB,$01',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FE,$01',$0A"; //SEND A RESPONSE...(DON'T ECHO)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$06',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO TIMING MARK)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$06',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$06',$0A"; //SEND A RESPONSE...(WON'T TIMING MARK)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$00',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO BINARY TRANSMISSION)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$00',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$00',$0A"; //SEND A RESPONSE...(WON'T BINARY TRANSMISSION)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FB,$03',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(WILL SUPPRESS GO AHEAD)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FB,$03',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FE,$03',$0A"; //SEND A RESPONSE...(DON'T SUPPRESS GO AHEAD)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FB,$01',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(WILL ECHO)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FB,$01',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FE,$01',$0A"; //SEND A RESPONSE...(DON'T ECHO)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$FF,$FD,$0A',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(DO USE CARRIAGE RETURN)
{
REMOVE_STRING(sMixerBuffer,'$FF,$FD,$0A',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
SEND_STRING dvMIXER_IP, "'$FF,$FC,$0A',$0A"; //SEND A RESPONSE...(WON'T USE CARRIAGE RETURN)
}
ELSE IF (FIND_STRING(sMixerBuffer,'$0D,$0A,Welcome to the Tesira Text Protocol Server,$0D,$0A',1)) //IF THE SPECIFIED STRING (sMixerBuffer) CONTAINS THE SPECIFIED SEQUENCE OF CHARACTERS...(WELCOME...)
{
REMOVE_STRING(sMixerBuffer,'$0D,$0A,Welcome to the Tesira Text Protocol Server,$0D,$0A',1) //This function removes characters from the specified string. All characters up to and including the first occurrence of the specified sequence are removed.
}
ELSE
{
CLEAR_BUFFER sMixerBuffer //This command sets the contents of the specified text buffer to zero; therefore, subsequent GET_BUFFER_CHAR calls will not return anything. The CLEAR_BUFFER command does not modify the data in the buffer, just the internal length value.
}
}
ONERROR:
{
//
}
}
I did not do anything with ONERROR, as I have not yet had problems.
The data event checks for and parses all the suggested possible negotiation strings, as documented in the Biamp Tesira Text Protocol manual.
I hope this saves someone some time. This forum has saved me a considerable amount of time over the years. Thank you.
Nice! Thanks for posting. The detailed documentation on session negotiation is particularly sweet.
If anyone is willing to share the trick of getting this forum to show space/tab indents in code posts, it would be appreciated. Thanks.
I would happily upload an AXS file with my code snippets, or post with a best practice. Can't find the help files for this forum. Some stuff is just too darn technical. Sigh.
No, that can't be right... according to the footnote it's made with
. Clearly, you're wrong... 
After reviewing the variable keywords in the Netlinx manual, it appears as though I declared the buffer as NONVOLATILE mistakenly. I do indeed wish to have the buffer cleared at power-down or reload. Thanks for bringing this to my attention, JasonS.
This should be easier to read.
and
//and
Oh yeah, probably not a "best practice" to post code with credentials...