From f175a0c0d5df8409455eba05a02ede893cd74baa Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Sat, 8 Feb 2020 18:57:01 +0000 Subject: [PATCH 1/2] Backported WJSendPlugin for controlling Panasonic video mixers - tested on WJ-MX30, but probably works for the MX50 and AVEs, too --- plugins/WJSendPlugin.py | 161 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 plugins/WJSendPlugin.py diff --git a/plugins/WJSendPlugin.py b/plugins/WJSendPlugin.py new file mode 100644 index 0000000..82ef0cd --- /dev/null +++ b/plugins/WJSendPlugin.py @@ -0,0 +1,161 @@ +import serial +from serial import Serial +import data_centre.plugin_collection +from data_centre.plugin_collection import ActionsPlugin, SequencePlugin +import threading + +class WJSendPlugin(ActionsPlugin,SequencePlugin): + disabled = False#True + ser = None + # from http://depot.univ-nc.nc/sources/boxtream-0.9999/boxtream/switchers/panasonic.py + """serial.Serial(device, baudrate=9600, + bytesize=serial.SEVENBITS, + parity=serial.PARITY_ODD, + stopbits=serial.STOPBITS_ONE, + xonxoff=False, + rtscts=True, # TODO : test without this one + timeout=timeout)""" + + commands = "GRAEIVXYZ012345Cgraeivxyzc" + macros = [] + + THROTTLE = 1 # milliseconds to wait between refreshing parameters + + def __init__(self, plugin_collection): + super().__init__(plugin_collection) + + if self.disabled: + print ("WJSendPlugin is disabled, not opening serial") + return + + #self.open_serial() + #print ("starting refresh?") + self.pc.actions.tk.after(500, self.refresh) + #tk.after(500, self.refresh) + + + def open_serial(self, port='/dev/ttyUSB0', baudrate=9600): + if self.ser is not None: + self.ser.close() + try: + self.ser = serial.Serial( + port=port, + baudrate=baudrate, + bytesize=serial.SEVENBITS, + parity=serial.PARITY_ODD, + stopbits=serial.STOPBITS_ONE, + xonxoff=False, + rtscts=True, # TODO : test without this one + timeout=None #timeout + ) + + print ("starting refresh?") + + #self.pc.midi_input.root.after(500, self.refresh) + except Exception as e: + print ("open_serial failed: " + str(type(e))) + import traceback + traceback.print_exc() + + @property + def parserlist(self): + return [ + ( r"^send_serial_macro_([0-9])$", self.send_serial_macro ), + ( r"^send_serial_string_(.*)$", self.send_serial_string ), + #( r"^send_random_colour$", self.send_random_settings ), + ( r"^open_serial$", self.open_serial ), + ( r"^wj_send_serial_([0-9a-zA-Z:]*)$", self.send_serial_string ), + ( r"^wj_set_colour_([A|B|T])_([x|y])$", self.set_colour ), + ( r"^wj_set_back_colour_([x|y|z])$", self.set_back_colour ), + ( r"^wj_set_position_([N|L])_([x|y])$", self.set_position ), + ( r"^wj_set_mix$", self.set_mix ), + ( r"^wj_send_append_pad_([0-9]*)_(([A-Z:[0-9a-zA-Z])$", self.send_append_pad ), + ( r"^wj_send_append_([A-Z:[0-9a-zA-Z])$", self.send_append ), + ] + + def send_serial_macro(self, macro): + self.send_serial_string(self.macros[macro]) + + def send_serial_string(self, string): + try: + print("sending string %s " % string) + output = b'\2' + string.encode('ascii') + b'\3' + self.ser.write(output) #.encode()) + print("sent string '%s'" % output) #.encode('ascii')) + #if 'S' in string: + # self.get_device_status() + except Exception as e: + print("%s: send_serial_string failed for '%s'" % (e,string.encode())) + + queue = {} + def refresh(self): + #print("refresh called!") + if not self.ser or self.ser is None: + self.open_serial() + + for queue, command in self.queue.items(): + self.send_buffered(queue, command) + self.queue.clear() + + self.pc.shaders.root.after(self.THROTTLE, self.refresh) + + def send(self, queue, output): + #self.send_buffered(queue,output) + self.queue[queue] = output + + last = {} + def send_buffered(self, queue, output): + if self.last.get(queue)!=output: + self.send_serial_string(output) + self.last[queue] = output + + colour_x = 127 + colour_y = 127 + def set_colour(self, chan, dim, value): + # chan can be A, B or T (both) + if dim=='x': + self.colour_x = int(255*value) + elif dim=='y': + self.colour_y = int(255*value) + + output = "VCC:{}{:02X}{:02X}".format(chan, self.colour_x,self.colour_y) #,random.randint(0,255)) + self.send('VCC', output) + + back_colour_x = 127 + back_colour_y = 127 + back_colour_z = 127 + def set_back_colour(self, dim, value): + # chan can be A, B or T (both) + if dim=='x': + self.back_colour_x = int(255*value) + elif dim=='y': + self.back_colour_y = int(255*value) + elif dim=='z': + self.back_colour_z = int(255*value) + + output = "VBM:{:02X}{:02X}{:02X}".format(self.back_colour_x,self.back_colour_y,self.back_colour_z) #,random.randint(0,255)) + self.send('VBM', output) + + position_x = 127 + position_y = 127 + def set_position(self, mode, dim, value): + if dim=='y': # yes, y is really x! + self.position_x = int(255*value) + elif dim=='x': # yes, x is really y! + self.position_y = int(255*value) + + output = "VPS:{}{:02X}{:02X}".format(mode,self.position_x,self.position_y) + self.send('VPS:{}'.format(mode), output) + + def set_mix(self, value): + output = "VMM:{:04X}".format(int(255*255*value)) + self.send('VMM', output) + + + def send_append(self, command, value): + # append value to the command as a hex value + self.send(command.split(':')[0], "{}{:02X}".format(command,int(255*value))) + + def send_append_pad(self, pad, command, value): + # append value, padded to length + self.send(command.split(':')[0], ("{}{:0%iX}"%pad).format(command,int(255*value))) From 10ddc2dbf29c70ad04ba50eb39203ec2e9a296bb Mon Sep 17 00:00:00 2001 From: Tristan Rowley Date: Sat, 8 Feb 2020 19:00:05 +0000 Subject: [PATCH 2/2] cleaned up, updated ACTIONS doc --- ACTIONS.md | 11 ++++++++++- plugins/WJSendPlugin.py | 9 --------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ACTIONS.md b/ACTIONS.md index b64198d..36859f8 100644 --- a/ACTIONS.md +++ b/ACTIONS.md @@ -1,6 +1,6 @@ # Auto-generated Actions list -Sat 1 Feb 00:15:28 UTC 2020 +Sat 8 Feb 18:58:59 UTC 2020 for branch=feature_plugins @@ -173,10 +173,12 @@ for branch=feature_plugins * set_shader_speed_layer_([0-2])_amount ### Plugin routes + * (.*)&&(.*) (from ManipulatePlugin) * invert|(.*) (from ManipulatePlugin) * f:(.*):|(.*) (from ManipulatePlugin) * set_variable_([a-zA-Z0-9]+) (from ManipulatePlugin) * ([A-Z0-9]+)>(.*) (from ManipulatePlugin) + * (.*)>&(.*) (from ManipulatePlugin) * (.*)&&(.*) (from MultiActionsPlugin) * test_plugin (from TestPlugin) * cycle_shaders (from TestPlugin) @@ -187,6 +189,13 @@ for branch=feature_plugins * toggle_loop_automation (from TestPlugin) * print_arguments (from TestPlugin) * set_the_shader_param_([0-3])_layer_offset_([0-2])_continuous_inverted_example (from TestPlugin) + * wj_send_serial_([0-9a-zA-Z:]*) (from WJSendPlugin) + * wj_set_colour_([A|B|T])_([x|y]) (from WJSendPlugin) + * wj_set_back_colour_([x|y|z]) (from WJSendPlugin) + * wj_set_position_([N|L])_([x|y]) (from WJSendPlugin) + * wj_set_mix (from WJSendPlugin) + * wj_send_append_pad_([0-9]*)_(([A-Z:[0-9a-zA-Z]) (from WJSendPlugin) + * wj_send_append_([A-Z:[0-9a-zA-Z]) (from WJSendPlugin) ---- diff --git a/plugins/WJSendPlugin.py b/plugins/WJSendPlugin.py index 82ef0cd..63a7b4d 100644 --- a/plugins/WJSendPlugin.py +++ b/plugins/WJSendPlugin.py @@ -16,9 +16,6 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin): rtscts=True, # TODO : test without this one timeout=timeout)""" - commands = "GRAEIVXYZ012345Cgraeivxyzc" - macros = [] - THROTTLE = 1 # milliseconds to wait between refreshing parameters def __init__(self, plugin_collection): @@ -60,9 +57,6 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin): @property def parserlist(self): return [ - ( r"^send_serial_macro_([0-9])$", self.send_serial_macro ), - ( r"^send_serial_string_(.*)$", self.send_serial_string ), - #( r"^send_random_colour$", self.send_random_settings ), ( r"^open_serial$", self.open_serial ), ( r"^wj_send_serial_([0-9a-zA-Z:]*)$", self.send_serial_string ), ( r"^wj_set_colour_([A|B|T])_([x|y])$", self.set_colour ), @@ -73,9 +67,6 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin): ( r"^wj_send_append_([A-Z:[0-9a-zA-Z])$", self.send_append ), ] - def send_serial_macro(self, macro): - self.send_serial_string(self.macros[macro]) - def send_serial_string(self, string): try: print("sending string %s " % string)