diff --git a/PJLink-TCP-Network-Command/README.md b/PJLink-TCP-Network-Command/README.md new file mode 100644 index 0000000..303745d --- /dev/null +++ b/PJLink-TCP-Network-Command/README.md @@ -0,0 +1,61 @@ +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 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!": + + ' 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 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 new file mode 100644 index 0000000..b91b389 --- /dev/null +++ b/PJLink-TCP-Network-Command/pjlink.brs @@ -0,0 +1,163 @@ +' 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 + ' s.dlog = pjlink_dlog + + ' 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 + ' 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" then + ' %1INPT 31\r\n + command = "2531494E50542033310D0A" + elseif fields[1] = "input-to-hdmi" then + ' %1INPT 32\r\n + command = "2531494E50542033320D0A" + elseif fields[1] = "shutter-open" then + ' %1AVMT 30\r\n + command = "253141564D542033300D0A" + elseif fields[1] = "shutter-closed" then + ' %1AVMT 31\r\n + command = "253141564D542033310D0A" + 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 + +' 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