From 60534d40253c70734d0ef8e7f2b43bbef3de08c6 Mon Sep 17 00:00:00 2001 From: Nathan Hyde Date: Tue, 6 Oct 2015 13:33:58 -0700 Subject: [PATCH 1/7] Add generic PJLink plugin. In addition to providing "named" poweron and poweroff commands, the pjlink plugin enables any pjlink command to be sent through a BrightSign. --- PJLink-TCP-Network-Command/README.md | 52 ++++++++++ PJLink-TCP-Network-Command/pjlink.brs | 137 ++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 PJLink-TCP-Network-Command/README.md create mode 100644 PJLink-TCP-Network-Command/pjlink.brs diff --git a/PJLink-TCP-Network-Command/README.md b/PJLink-TCP-Network-Command/README.md new file mode 100644 index 0000000..a03cb4f --- /dev/null +++ b/PJLink-TCP-Network-Command/README.md @@ -0,0 +1,52 @@ +Overview +------------ + +This plugin allows a BrightSign to operate and control a projector using the [PJLink](http://pjlink.jbmia.or.jp/english/) standard. PJLink commands are sent as hexadecimal-formatted messages over the local network using a TCP connection. + +## Installation + +In BrightAuthor, while editing a presentation, open the Autorun presentation properties at **File > Presentation Properties > Autorun**. + +1. Add a new *Script Plugin*: + + * **Name**: _pjlink_ (in all lowercase letters) + * **Path**: Select `pjlink.brs` as the path. + +2. Set the PJLink IP Address and optionally the TCP port number. Create two **User Variables** by going to **File > Presentation Properties > Variables** and adding the following: + * **pjlink_projector_ip** - set the default to your projector's IP Address + * **pjlink_projector_port** - (optional) set to the TCP port number to address the projector. If this variable is not set the plugin will use port **4352**. + + +## Usage + +This plugin includes two named commands: "poweron" and "poweroff". Otherwise actual raw PJLink commands can be sent as well. + +There are two methods of usage for this plugin: + +1. Using Send Plugin Message in an interactive presentation: + * **Advanced > Send > Send Plugin Message**. Select the "pjlink" plugin. In the parameters block, enter on of the following: + * **poweron** + * **poweroff** + * Any raw PJLink command, such as **INPT 32** to switch to the digital input. + +2. Direct messaging with UDP datagrams. Commands must be prefixed with "pjlink!": + + # Named commands from this plugin: + # power the projector on and off + pjlink!poweron + pjlink!poweroff + + # "Raw" PJLink commands. Format: pjlink! + # power the projector on and off: + pjlink!POWR 1 + # power the projector off: + pjlink!POWR 0 + # switch inputs: + pjlink!INPT 11 + pjlink!INPT 32 + +## Testing + +The [PJLink Test software](http://pjlink.jbmia.or.jp/english/dl.html) can be used to confirm commands are being sent/processed not the projector end. (Configure the Network under the Set up menu of the PJLinkTest4PJ exe.) + +With telnet enabled on you can see messages from the pjlink plugin printed to the screen. Connection details (IP and port) as well as hex-encoded commands are printed. \ No newline at end of file diff --git a/PJLink-TCP-Network-Command/pjlink.brs b/PJLink-TCP-Network-Command/pjlink.brs new file mode 100644 index 0000000..9b9ea5f --- /dev/null +++ b/PJLink-TCP-Network-Command/pjlink.brs @@ -0,0 +1,137 @@ +' Based on PJLinkOn BrightSign Plugin by Tweaklab +' v1.00 + +Function pjlink_Initialize(msgPort As Object, userVariables As Object, bsp as Object) + print "pjlink_Initialize - entry" + + pjlink = newpjlink(msgPort, userVariables, bsp) + + return pjlink +End Function + +Function newpjlink(msgPort As Object, userVariables As Object, bsp As Object) + print "newpjlink" + s = {} + s.msgPort = msgPort + s.userVariables = userVariables + s.bsp = bsp + s.ProcessEvent = pjlink_ProcessEvent + + s.projector_ip$ = "" + s.projector_port = 4352 + s.debug = true + + ' SetParamsFromUserVariables(s, userVariables) + ' set IP address from user variables + if userVariables.DoesExist("pjlink_projector_ip") then + myvariable = userVariables.Lookup("pjlink_projector_ip") + if myvariable <> invalid then + s.projector_ip$ = myvariable.GetCurrentValue() + s.bsp.diagnostics.printdebug("set pjlink ip address: " + s.projector_ip$) + endif + endif + + ' set projector port + if userVariables.DoesExist("pjlink_projector_port") then + myvariable = userVariables.Lookup("pjlink_projector_port") + if myvariable <> invalid then + s.projector_port = myvariable.GetCurrentValue() + s.bsp.diagnostics.printdebug("set pjlink port: "+s.projector_port) + endif + endif + + return s +End Function + +Function pjlink_ProcessEvent(event As Object) as boolean + print "pjlink_ProcessEvent" + print " type of message is: ";type(m) + print " type of event is: ";type(event) + retval = false + + ' define the message "%1POWR 1" in HEX to power ON the projector + ' %1POWR 1 = Power On + ' projector_message$="2531504F575220310D0A" + + if type(event) = "roAssociativeArray" then + if type(event["EventType"]) = "roString" then + if event["EventType"] = "SEND_PLUGIN_MESSAGE" then + if event["PluginName"] = "pjlink" then + pluginMessage$ = event["PluginMessage"] + print "SEND_PLUGIN/EVENT_MESSAGE:";pluginMessage$ + messageToParse$ = event["PluginName"]+"!"+pluginMessage$ + retval = pjlink_ParsePluginMsg(messageToParse$, m) + endif + endif + endif + elseif type(event) = "roDatagramEvent" then + ' UDP Datagrams for pjlink! + msg$ = event + if (left(msg$,6) = "pjlink") then + retval = pjlink_ParsePluginMsg(msg$, m) + endif + endif + + return retval +End Function + +Function pjlink_ParsePluginMsg(msg As string, s As Object) as boolean + print "pjlink_ParsePluginMsg" + retval = false + + r = CreateObject("roRegex", "^pjlink", "i") + match = r.IsMatch(msg) + if match then + retval = true + command = "" + + r2 = CreateObject("roRegex", "!", "i") + fields = r2.split(msg) + numFields = fields.count() + if (numFields < 2) or (numFields > 2) then + s.bsp.diagnostics.printdebug("pjlink Incorrect number of fields for command:"+msg) + return retval + else + ' numFields = 2 + if fields[1] = "poweron" then + command = "2531504F575220310D0A" + elseif fields[1] = "poweroff" then + command = "2531504F575220300D0A" + else + ' append %1 and \r\n to the command + ba = CreateObject("roByteArray") + ba.FromAsciiString("%1" + fields[1] + Chr(13) + Chr(10)) + command = ba.ToHexString() + endif + endif + ' s.bsp.diagnostics.printdebug("pjlink command found: " +command) + print "pjlink command assigned: ";command + retval = pjlink_SendProjectorMessage(command, s) + endif + + return retval +End Function + +Function pjlink_SendProjectorMessage(hex_msg as string, s As Object) as boolean + print "Connecting to projector at ";s.projector_ip$; ":";s.projector_port + + sock=CreateObject("roTCPStream") + if sock=invalid then + print "Failed to create roTCPClient object" + stop + endif + if sock.ConnectTo(s.projector_ip$, StrToI(s.projector_port)) then + ' print "Connected" + bytes = CreateObject("roByteArray") + sleep(500) + bytes.FromHexString(hex_msg) + print "Sending PJLink message: ";hex_msg + sock.SendBlock(bytes) + return true + else + print "Failed to connect to projector" + sock = invalid + endif + + return false +End Function From 3f6e24db468cc7a7fb63ae273c0a4ebb9ab30692 Mon Sep 17 00:00:00 2001 From: Nathan Hyde Date: Thu, 5 Nov 2015 14:00:52 -0800 Subject: [PATCH 2/7] Update README.md Correct typo in README. "on of the following" -> "one of the following". --- PJLink-TCP-Network-Command/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PJLink-TCP-Network-Command/README.md b/PJLink-TCP-Network-Command/README.md index a03cb4f..3c284f3 100644 --- a/PJLink-TCP-Network-Command/README.md +++ b/PJLink-TCP-Network-Command/README.md @@ -24,7 +24,7 @@ This plugin includes two named commands: "poweron" and "poweroff". Otherwise act There are two methods of usage for this plugin: 1. Using Send Plugin Message in an interactive presentation: - * **Advanced > Send > Send Plugin Message**. Select the "pjlink" plugin. In the parameters block, enter on of the following: + * **Advanced > Send > Send Plugin Message**. Select the "pjlink" plugin. In the parameters block, enter one of the following: * **poweron** * **poweroff** * Any raw PJLink command, such as **INPT 32** to switch to the digital input. @@ -49,4 +49,4 @@ There are two methods of usage for this plugin: The [PJLink Test software](http://pjlink.jbmia.or.jp/english/dl.html) can be used to confirm commands are being sent/processed not the projector end. (Configure the Network under the Set up menu of the PJLinkTest4PJ exe.) -With telnet enabled on you can see messages from the pjlink plugin printed to the screen. Connection details (IP and port) as well as hex-encoded commands are printed. \ No newline at end of file +With telnet enabled on you can see messages from the pjlink plugin printed to the screen. Connection details (IP and port) as well as hex-encoded commands are printed. From a4e5426f996fe0fff0eaec40121cbec9dcc0cb7e Mon Sep 17 00:00:00 2001 From: Nathan Hyde Date: Thu, 14 Jan 2016 15:54:20 -0800 Subject: [PATCH 3/7] Debug log method. (From downplay.brs) --- PJLink-TCP-Network-Command/pjlink.brs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/PJLink-TCP-Network-Command/pjlink.brs b/PJLink-TCP-Network-Command/pjlink.brs index 9b9ea5f..794072e 100644 --- a/PJLink-TCP-Network-Command/pjlink.brs +++ b/PJLink-TCP-Network-Command/pjlink.brs @@ -20,6 +20,7 @@ Function newpjlink(msgPort As Object, userVariables As Object, bsp As Object) s.projector_ip$ = "" s.projector_port = 4352 s.debug = true + ' s.dlog = pjlink_dlog ' SetParamsFromUserVariables(s, userVariables) ' set IP address from user variables @@ -135,3 +136,11 @@ Function pjlink_SendProjectorMessage(hex_msg as string, s As Object) as boolean return false End Function + +' Sub pjlink_dlog (error$ as String) +' m.bsp.logging.WriteDiagnosticLogEntry("99plgn", error$) +' 'm.bsp.diagnostics.printdebug(error$) +' print error$ +' slog = createobject("roSystemLog") +' slog.sendline(error$) +' End Sub From 6d261bfd1adebd327d1838ef183258194e6864b4 Mon Sep 17 00:00:00 2001 From: Nathan Hyde Date: Fri, 15 Jan 2016 15:43:08 -0800 Subject: [PATCH 4/7] README.md Testing section update. Correct word usage in Testing section. --- PJLink-TCP-Network-Command/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PJLink-TCP-Network-Command/README.md b/PJLink-TCP-Network-Command/README.md index 3c284f3..43fc3bd 100644 --- a/PJLink-TCP-Network-Command/README.md +++ b/PJLink-TCP-Network-Command/README.md @@ -35,7 +35,7 @@ There are two methods of usage for this plugin: # power the projector on and off pjlink!poweron pjlink!poweroff - + # "Raw" PJLink commands. Format: pjlink! # power the projector on and off: pjlink!POWR 1 @@ -47,6 +47,6 @@ There are two methods of usage for this plugin: ## Testing -The [PJLink Test software](http://pjlink.jbmia.or.jp/english/dl.html) can be used to confirm commands are being sent/processed not the projector end. (Configure the Network under the Set up menu of the PJLinkTest4PJ exe.) +The [PJLink Test software](http://pjlink.jbmia.or.jp/english/dl.html) can be used to confirm commands are being sent/processed on the projector end. (Configure the Network under the Set up menu of the PJLinkTest4PJ exe.) -With telnet enabled on you can see messages from the pjlink plugin printed to the screen. Connection details (IP and port) as well as hex-encoded commands are printed. +With telnet enabled on the BrightSign unit you can see messages from the pjlink plugin printed to the screen. Connection details (IP and port) as well as hex-encoded commands are printed. From 568cfdca08ce407b82fad35924ebf447d93b2ae8 Mon Sep 17 00:00:00 2001 From: Nathan Hyde Date: Fri, 15 Jan 2016 15:49:33 -0800 Subject: [PATCH 5/7] PJLink/README - Use BrightScript style comments in command usage block --- PJLink-TCP-Network-Command/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PJLink-TCP-Network-Command/README.md b/PJLink-TCP-Network-Command/README.md index 43fc3bd..5aa9ac1 100644 --- a/PJLink-TCP-Network-Command/README.md +++ b/PJLink-TCP-Network-Command/README.md @@ -31,17 +31,17 @@ There are two methods of usage for this plugin: 2. Direct messaging with UDP datagrams. Commands must be prefixed with "pjlink!": - # Named commands from this plugin: - # power the projector on and off + ' Named commands from this plugin: + ' power the projector on and off pjlink!poweron pjlink!poweroff - # "Raw" PJLink commands. Format: pjlink! - # power the projector on and off: + ' "Raw" PJLink commands. Format: pjlink! + ' power the projector on and off: pjlink!POWR 1 - # power the projector off: + ' power the projector off: pjlink!POWR 0 - # switch inputs: + ' switch inputs: pjlink!INPT 11 pjlink!INPT 32 From 05476109450a3f1a6b65a74d2ef6846c538395ff Mon Sep 17 00:00:00 2001 From: Nathan Hyde Date: Fri, 23 Sep 2016 10:46:21 -0700 Subject: [PATCH 6/7] Add input-to-* and shutter-(open|closed) named commands. Added note as to how to create the pre-baked command hex string to code and README. --- PJLink-TCP-Network-Command/README.md | 9 +++++++++ PJLink-TCP-Network-Command/pjlink.brs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/PJLink-TCP-Network-Command/README.md b/PJLink-TCP-Network-Command/README.md index 5aa9ac1..303745d 100644 --- a/PJLink-TCP-Network-Command/README.md +++ b/PJLink-TCP-Network-Command/README.md @@ -27,6 +27,10 @@ There are two methods of usage for this plugin: * **Advanced > Send > Send Plugin Message**. Select the "pjlink" plugin. In the parameters block, enter one of the following: * **poweron** * **poweroff** + * **input-to-dvi** + * **input-to-hdmi** + * **shutter-open** + * **shutter-closed** * Any raw PJLink command, such as **INPT 32** to switch to the digital input. 2. Direct messaging with UDP datagrams. Commands must be prefixed with "pjlink!": @@ -50,3 +54,8 @@ There are two methods of usage for this plugin: The [PJLink Test software](http://pjlink.jbmia.or.jp/english/dl.html) can be used to confirm commands are being sent/processed on the projector end. (Configure the Network under the Set up menu of the PJLinkTest4PJ exe.) With telnet enabled on the BrightSign unit you can see messages from the pjlink plugin printed to the screen. Connection details (IP and port) as well as hex-encoded commands are printed. + +To generate the required hex string for additional pre-baked commands, try this in csharp: + + string cmd = "INPT 31" + BitConverter.ToString(System.Text.Encoding.ASCII.GetBytes("%1" + cmd + "\r\n")).Replace("-", "") diff --git a/PJLink-TCP-Network-Command/pjlink.brs b/PJLink-TCP-Network-Command/pjlink.brs index 794072e..ec81352 100644 --- a/PJLink-TCP-Network-Command/pjlink.brs +++ b/PJLink-TCP-Network-Command/pjlink.brs @@ -94,10 +94,27 @@ Function pjlink_ParsePluginMsg(msg As string, s As Object) as boolean return retval else ' numFields = 2 + ' To generate additional pre-baked commands, try this in csharp: + ' string cmd = "INPT 31" + ' BitConverter.ToString(System.Text.Encoding.ASCII.GetBytes("%1" + cmd + "\r\n")).Replace("-", "") if fields[1] = "poweron" then + ' %1POWR 1\r\n command = "2531504F575220310D0A" elseif fields[1] = "poweroff" then + ' %1POWR 0\r\n command = "2531504F575220300D0A" + elseif fields[1] = "input-to-dvi" + ' %1INPT 31\r\n + command = "2531494E50542033310D0A" + elseif fields[1] = "input-to-hdmi" + ' %1INPT 32\r\n + command = "2531494E50542033320D0A" + elseif fields[1] = "shutter-open" + ' %1AVMT 30\r\n + command = "253141564D542033300D0A" + elseif fields[1] = "shutter-closed" + ' %1AVMT 31\r\n + command = "253141564D542033310D0A" else ' append %1 and \r\n to the command ba = CreateObject("roByteArray") From d2256cf4acd4bd0e4def9ec5d52c8c4e124e5964 Mon Sep 17 00:00:00 2001 From: Nathan Hyde Date: Fri, 23 Sep 2016 10:52:20 -0700 Subject: [PATCH 7/7] if/then in pjlink plugin named commands. --- PJLink-TCP-Network-Command/pjlink.brs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PJLink-TCP-Network-Command/pjlink.brs b/PJLink-TCP-Network-Command/pjlink.brs index ec81352..b91b389 100644 --- a/PJLink-TCP-Network-Command/pjlink.brs +++ b/PJLink-TCP-Network-Command/pjlink.brs @@ -103,16 +103,16 @@ Function pjlink_ParsePluginMsg(msg As string, s As Object) as boolean elseif fields[1] = "poweroff" then ' %1POWR 0\r\n command = "2531504F575220300D0A" - elseif fields[1] = "input-to-dvi" + elseif fields[1] = "input-to-dvi" then ' %1INPT 31\r\n command = "2531494E50542033310D0A" - elseif fields[1] = "input-to-hdmi" + elseif fields[1] = "input-to-hdmi" then ' %1INPT 32\r\n command = "2531494E50542033320D0A" - elseif fields[1] = "shutter-open" + elseif fields[1] = "shutter-open" then ' %1AVMT 30\r\n command = "253141564D542033300D0A" - elseif fields[1] = "shutter-closed" + elseif fields[1] = "shutter-closed" then ' %1AVMT 31\r\n command = "253141564D542033310D0A" else