changeset 1972:d4a07ad96aad

attempt a pyftdi output driver using code from https://github.com/jlbrogdon/dmx_controller/blob/master/OpenDmxUsb/__init__.py (gplv2) Ignore-this: 5a4dbbc0493dfa0bf62cc9c5b79b96d7
author drewp@bigasterisk.com
date Sat, 08 Jun 2019 07:36:34 +0000
parents b26a1e7fcfbe
children aebe823b2414
files light9/collector/dmx_controller_output.py light9/collector/output.py requirements.txt
diffstat 3 files changed, 87 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/collector/dmx_controller_output.py	Sat Jun 08 07:36:34 2019 +0000
@@ -0,0 +1,58 @@
+#######################################################
+# DMX Controller
+# See <TBD>
+# Copyright (C) Jonathan Brogdon <jlbrogdon@gmail.com>
+# This program is published under a GPLv2 license
+#
+# This code implements a DMX controller with UI provided
+# by LCDproc
+#
+#######################################################
+from pyftdi import ftdi
+
+#FTDI device info
+vendor=0x0403
+product=0x6001
+
+#####################
+# DMX USB controller
+#####################
+class OpenDmxUsb():
+    def __init__(self):
+        self.baud_rate = 250000
+        self.data_bits = 8
+        self.stop_bits = 2
+        self.parity = 'N'
+        self.flow_ctrl = ''
+        self.rts_state = 0
+        self._init_dmx()
+
+    #Initialize the controller
+    def _init_dmx(self):
+        self.ftdi=ftdi.Ftdi()
+        self.ftdi.open(vendor,product,0)
+        self.ftdi.set_baudrate(self.baud_rate)
+        self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=0)
+        self.ftdi.set_flowctrl(self.flow_ctrl)
+        self.ftdi.purge_rx_buffer()
+        self.ftdi.purge_tx_buffer()
+        self.ftdi.set_rts(self.rts_state)
+
+    #Send DMX data
+    def send_dmx(self,channelVals):
+        assert self.ftdi.write_data(channelVals) == 513
+        # Need to generate two bits for break
+        self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=1)
+        self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=1)
+        self.ftdi.set_line_property(self.data_bits,self.stop_bits,self.parity,break_=0)            
+
+if __name__=="__main__":
+    dmxUsb=OpenDmxUsb()
+
+    channelVals=bytearray([0]*513)
+    channelVals[0]=0 # dummy channel 0
+    while(True):
+        for x in range(1,468+1):
+            channelVals[x] = 255
+
+        dmxUsb.send_dmx(channelVals)
--- a/light9/collector/output.py	Sat Jun 08 03:54:01 2019 +0000
+++ b/light9/collector/output.py	Sat Jun 08 07:36:34 2019 +0000
@@ -102,6 +102,34 @@
         d = threads.deferToThread(self._write, sendingBuffer)
         d.addCallbacks(done, err)
 
+class FtdiDmx(BackgroundLoopOutput):
+    def __init__(self, uri, lastDmxChannel, rate=22):
+        super().__init__(uri)
+        self.lastDmxChannel = lastDmxChannel
+        from .dmx_controller_output import OpenDmxUsb
+        self.dmx = OpenDmxUsb()
+        
+    def _write(self, buf):
+        self._writeStats.fps.mark()
+        with self._writeStats.call.time():
+            if not buf:
+                logAllDmx.debug('%s: empty buf- no output',
+                                self.shortId())
+                return
+
+            # ok to truncate the last channels if they just went
+            # to 0? No it is not. DMX receivers don't add implicit
+            # zeros there.
+            buf = bytes([0]) + buf[:self.lastDmxChannel]
+
+            if logAllDmx.isEnabledFor(logging.DEBUG):
+                # for testing fps, smooth fades, etc
+                logAllDmx.debug(
+                    '%s: %s...' %
+                    (self.shortId(), ' '.join(map(str, buf[:32]))))
+
+            self.dmx.send_dmx(buf)
+
 
 class Udmx(BackgroundLoopOutput):
     _reconnections = scales.IntStat('reconnections')
--- a/requirements.txt	Sat Jun 08 03:54:01 2019 +0000
+++ b/requirements.txt	Sat Jun 08 07:36:34 2019 +0000
@@ -46,3 +46,4 @@
 cycloneerr==0.3.0
 rdfdb==0.20.0
 standardservice==0.6.0
+pyftdi==0.29.4