summaryrefslogtreecommitdiff
path: root/df10ch_setup_pkg
diff options
context:
space:
mode:
authorAndreas Auras <yak54@gmx.net>2010-02-09 15:30:49 +0100
committerAndreas Auras <yak54@gmx.net>2010-02-09 15:30:49 +0100
commit69175ad4105845f2a766c308aa246cc0b624ac08 (patch)
tree588fc8b28f47bc7e385e8f0feb346f488086da80 /df10ch_setup_pkg
downloaddf10ch-atmolight-controller-69175ad4105845f2a766c308aa246cc0b624ac08.tar.gz
df10ch-atmolight-controller-69175ad4105845f2a766c308aa246cc0b624ac08.tar.bz2
First import into git
Diffstat (limited to 'df10ch_setup_pkg')
-rw-r--r--df10ch_setup_pkg/__init__.py21
-rw-r--r--df10ch_setup_pkg/areas_dlg.py235
-rw-r--r--df10ch_setup_pkg/bright_dlg.py83
-rw-r--r--df10ch_setup_pkg/device_dlg.py428
-rw-r--r--df10ch_setup_pkg/device_drv.py1011
-rw-r--r--df10ch_setup_pkg/firmware.py135
-rw-r--r--df10ch_setup_pkg/layout_dlg.py111
-rw-r--r--df10ch_setup_pkg/map_dlg.py256
-rw-r--r--df10ch_setup_pkg/setup_dlg.py58
-rw-r--r--df10ch_setup_pkg/white_cal_dlg.py172
10 files changed, 2510 insertions, 0 deletions
diff --git a/df10ch_setup_pkg/__init__.py b/df10ch_setup_pkg/__init__.py
new file mode 100644
index 0000000..4ce758a
--- /dev/null
+++ b/df10ch_setup_pkg/__init__.py
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+# \ No newline at end of file
diff --git a/df10ch_setup_pkg/areas_dlg.py b/df10ch_setup_pkg/areas_dlg.py
new file mode 100644
index 0000000..3eeb8c7
--- /dev/null
+++ b/df10ch_setup_pkg/areas_dlg.py
@@ -0,0 +1,235 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+from Tkinter import *
+import device_drv
+
+class AreasDialog:
+ def __init__(self, master=None, **args):
+ self.root = Canvas(master, **args)
+ self.selectedArea = None
+ self.selectCallbacks = list()
+
+ def configAreas(self, numAreas):
+ nTopLeft = numAreas[device_drv.AreaIndex("TopLeft")]
+ nTopRight = numAreas[device_drv.AreaIndex("TopRight")]
+ nBottomLeft = numAreas[device_drv.AreaIndex("BottomLeft")]
+ nBottomRight = numAreas[device_drv.AreaIndex("BottomRight")]
+ nCenter = numAreas[device_drv.AreaIndex("Center")]
+ nTop = numAreas[device_drv.AreaIndex("Top")]
+ nBottom = numAreas[device_drv.AreaIndex("Bottom")]
+ nLeft = numAreas[device_drv.AreaIndex("Left")]
+ nRight = numAreas[device_drv.AreaIndex("Right")]
+
+ cv = self.root
+ size = 0
+ width = int(cv["width"])
+ height = int(cv["height"])
+
+ sTop = nTop + nTopLeft + nTopRight
+ if sTop:
+ topSize = int(width / sTop)
+ topSizeEnd = width - topSize * (sTop - 1)
+ if not size or topSize < size:
+ size = topSize
+
+ sBottom = nBottom + nBottomLeft + nBottomRight
+ if sBottom:
+ bottomSize = int(width / sBottom)
+ bottomSizeEnd = width - bottomSize * (sBottom - 1)
+ if not size or bottomSize < size:
+ size = bottomSize
+
+ sLeft = nLeft + nTopLeft + nBottomLeft
+ if sLeft:
+ leftSize = int(height / sLeft)
+ leftSizeEnd = height - leftSize * (sLeft - 1)
+ if not size or leftSize < size:
+ size = leftSize
+
+ sRight = nRight + nTopRight + nBottomRight
+ if sRight:
+ rightSize = int(height / sRight)
+ rightSizeEnd = height - rightSize * (sRight - 1)
+ if not size or rightSize < size:
+ size = rightSize
+
+ if not size or int(width / 2) < size:
+ size = int(width / 2)
+ if not size or int(height / 2) < size:
+ size = int(height / 2)
+
+ pTop = [ None ] * nTop
+ x = 0
+
+ # top left corner
+ if nTopLeft:
+ pTopLeft = [ 0, 0, topSize, 0, topSize, size, size, size, size, leftSize, 0, leftSize ]
+ x = topSize
+ elif nTop == 1:
+ pTop[0] = [ 0, 0, width, 0, width - size, size, size, size ]
+ elif nTop > 1:
+ pTop[0] = [ 0, 0, topSize, 0, topSize, size, size, size ]
+
+ # top right corner
+ if nTopRight:
+ pTopRight = [ width, 0, width, rightSize, width - size, rightSize, width - size, size, width - topSizeEnd, size, width - topSizeEnd, 0 ]
+ elif nTop > 1:
+ pTop[nTop - 1] = [ width, 0, width - size, size, width - topSizeEnd, size, width - topSizeEnd, 0 ]
+
+ # top
+ for i in range(nTop):
+ if pTop[i] == None:
+ pTop[i] = [ x, 0, x + topSize, 0, x + topSize, size, x, size ]
+ x = x + topSize
+
+ pBottom = [ None ] * nBottom
+ x = 0
+
+ # bottom left corner
+ if nBottomLeft:
+ pBottomLeft = [ 0, height, 0, height - leftSizeEnd, size, height - leftSizeEnd, size, height - size, bottomSize, height - size, bottomSize, height ]
+ x = bottomSize
+ elif nBottom == 1:
+ pBottom[0] = [ 0, height, size, height - size, width - size, height - size, width, height ]
+ elif nBottom > 1:
+ pBottom[0] = [ 0, height, size, height - size, bottomSize, height - size, bottomSize, height ]
+
+ # bottom right corner
+ if nBottomRight:
+ pBottomRight = [ width, height, width - bottomSizeEnd, height, width - bottomSizeEnd, height - size, width - size, height - size, width - size, height - rightSizeEnd, width, height - rightSizeEnd ]
+ elif nBottom > 1:
+ pBottom[nBottom - 1] = [ width, height, width - bottomSizeEnd, height, width - bottomSizeEnd, height - size, width - size, height - size ]
+
+ # bottom
+ for i in range(nBottom):
+ if pBottom[i] == None:
+ pBottom[i] = [ x, height, x, height - size, x + bottomSize, height - size, x + bottomSize, height ]
+ x = x + bottomSize
+
+ pLeft = [ None ] * nLeft
+ y = 0
+
+ # left top corner
+ if nTopLeft:
+ y = leftSize
+ elif nLeft == 1:
+ pLeft[0] = [ 0, 0, size, size, size, height - size, 0, height ]
+ elif nLeft > 1:
+ pLeft[0] = [ 0, 0, size, size, size, leftSize, 0, leftSize ]
+
+ # left bottom corner
+ if not nBottomLeft and nLeft > 1:
+ pLeft[nLeft - 1] = [ 0, height, 0, height - leftSizeEnd, size, height - leftSizeEnd, size, height - size ]
+
+ # left
+ for i in range(nLeft):
+ if pLeft[i] == None:
+ pLeft[i] = [ 0, y, size, y, size, y + leftSize, 0, y + leftSize ]
+ y = y + leftSize
+
+ pRight = [ None ] * nRight
+ y = 0
+
+ # right top corner
+ if nTopRight:
+ y = rightSize
+ elif nRight == 1:
+ pRight[0] = [ width, 0, width, height, width - size, height - size, width - size, size ]
+ elif nRight > 1:
+ pRight[0] = [ width, 0, width, rightSize, width - size, rightSize, width - size, size ]
+
+ # right bottom corner
+ if not nBottomRight and nRight > 1:
+ pRight[nRight - 1] = [ width, height, width - size, height - size, width - size, height - rightSizeEnd, width, height - rightSizeEnd ]
+
+ # right
+ for i in range(nRight):
+ if pRight[i] == None:
+ pRight[i] = [ width, y, width, y + rightSize, width - size, y + rightSize, width - size, y ]
+ y = y + rightSize
+
+ # center
+ if nCenter:
+ pCenter = [ size, size, width - size, size, width - size, height - size, size, height - size ]
+
+ # Build canvas items
+ cv.delete(ALL)
+
+ if nTopLeft:
+ cv.create_polygon(pTopLeft, tags="TopLeft")
+ if nTopRight:
+ cv.create_polygon(pTopRight, tags="TopRight")
+ if nBottomLeft:
+ cv.create_polygon(pBottomLeft, tags="BottomLeft")
+ if nBottomRight:
+ cv.create_polygon(pBottomRight, tags="BottomRight")
+ if nCenter:
+ cv.create_polygon(pCenter, tags="Center")
+
+ for i in range(nTop):
+ cv.create_polygon(pTop[i], tags="Top-{0}".format(i + 1))
+ for i in range(nBottom):
+ cv.create_polygon(pBottom[i], tags="Bottom-{0}".format(i + 1))
+ for i in range(nLeft):
+ cv.create_polygon(pLeft[i], tags="Left-{0}".format(i + 1))
+ for i in range(nRight):
+ cv.create_polygon(pRight[i], tags="Right-{0}".format(i + 1))
+
+ for id in cv.find_all():
+ cv.itemconfigure(id, outline="#808080", width=3)
+ cv.tag_bind(id, "<Button-1>", self.cbSelectArea)
+
+ def initAreas(self, color):
+ self.root.configure(background=color)
+ for id in self.root.find_all():
+ self.root.itemconfigure(id, fill=color, outline="#808080")
+ self.selectedArea = None
+
+ def setAreaColor(self, area, color):
+ self.root.itemconfigure(area, fill=color)
+
+ def selectArea(self, area):
+ if self.selectedArea != area:
+ cv = self.root
+ if self.selectedArea:
+ cv.itemconfigure(self.selectedArea, outline="#808080")
+ idList = cv.find_withtag(area)
+ if len(idList):
+ id = idList[0]
+ cv.tag_raise(id)
+ cv.itemconfigure(id, outline="yellow")
+ self.selectedArea = area
+
+ def cbSelectArea(self, event):
+ cv = self.root
+ idList = cv.find_closest(cv.canvasx(event.x), cv.canvasx(event.y))
+ if len(idList):
+ id = idList[0]
+ if self.selectedArea:
+ cv.itemconfigure(self.selectedArea, outline="#808080")
+ self.selectedArea = cv.gettags(id)[0]
+ cv.tag_raise(id)
+ cv.itemconfigure(id, outline="yellow")
+
+ for cb in self.selectCallbacks:
+ cb.cbAreaSelected()
diff --git a/df10ch_setup_pkg/bright_dlg.py b/df10ch_setup_pkg/bright_dlg.py
new file mode 100644
index 0000000..0bf8bf4
--- /dev/null
+++ b/df10ch_setup_pkg/bright_dlg.py
@@ -0,0 +1,83 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+from Tkinter import *
+import tkFont
+import tkMessageBox
+import device_drv
+
+
+class BrightDialog:
+ def __init__(self, areasDlg, master=None, **args):
+ self.areasDlg = areasDlg
+
+ root = Frame(master, **args)
+ self.root = root
+ root.bind("<Map>", self.cbSheetSelected)
+
+ Label(root, text="Common Brightness Calibration", font=tkFont.Font(weight="bold")).grid(row=0, column=0, columnspan=5, padx=5, pady=5)
+
+ self.varBright = DoubleVar()
+ self.scBright = Scale(root, label="Brightness", length=200, from_=0, to=1.0, resolution=0.01, orient=HORIZONTAL, variable=self.varBright, command=self.cbSetBright)
+ self.scBright.grid(row=1, column=0, rowspan=1, padx=20, pady=5)
+ self.varBright.set(0.0)
+
+ def cbSheetSelected(self, event):
+ self.loadValues()
+
+ def cbSetBright(self, val):
+ self.setBright()
+
+ def loadValues(self):
+ for ctrlId in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[ctrlId]
+ pwmChannelMap = list()
+ for portName in config.channelMap.keys():
+ configMapRec = config.channelMap[portName]
+ if configMapRec:
+ port, pin = device_drv.PORT_NAME_MAP[portName]
+ pwmChannelMap.append(dict(channel=0, port=port, pins=pin))
+
+ bright = float(config.commonBright) / float(config.commonPWMRes)
+ self.varBright.set(bright)
+
+ while len(pwmChannelMap) < device_drv.NCHANNELS:
+ pwmChannelMap.append(dict(channel=0, port=0, pins=0))
+
+ try:
+ config.ctrl.set_channel_map(0, pwmChannelMap)
+ config.ctrl.set_brightness(0, [ config.pwmRes ] + [ 0 ] * (device_drv.NCHANNELS - 1))
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ return
+
+ self.areasDlg.initAreas("black")
+ self.setBright()
+
+ def setBright(self):
+ try:
+ for ctrlId in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[ctrlId]
+ config.setCommonBright(int(round(self.varBright.get() * config.commonPWMRes)))
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
diff --git a/df10ch_setup_pkg/device_dlg.py b/df10ch_setup_pkg/device_dlg.py
new file mode 100644
index 0000000..a473117
--- /dev/null
+++ b/df10ch_setup_pkg/device_dlg.py
@@ -0,0 +1,428 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+from Tkinter import *
+import tkFont
+import tkMessageBox
+import tkFileDialog
+import usb
+import pickle
+import string
+import time
+
+import device_drv
+import firmware
+
+class DeviceDialog:
+ def __init__(self, layoutDlg, master=None, **args):
+ self.layoutDlg = layoutDlg
+ self.selectedConfig = None
+ self.selectedDeviceIdx = -1
+
+ root = Frame(master, **args)
+ self.root = root
+ root.bind("<Map>", self.cbSheetSelected)
+
+ Label(root, text="Device Control", font=tkFont.Font(weight="bold")).grid(row=0, column=0, columnspan=7, padx=5, pady=5)
+
+ self.varDeviceList = StringVar()
+ self.lbDevices = Listbox(root, selectmode=SINGLE, activestyle=NONE, width=20, height=8, listvariable=self.varDeviceList)
+ self.lbDevices.grid(row=1, column=0, columnspan=2, rowspan=4, padx=5, pady=5, sticky=N+S+E+W)
+ self.lbDevices.bind("<ButtonRelease-1>", self.cbSelectDevice)
+
+ self.varVersion = StringVar()
+ Label(root, text="Version:").grid(row=1, column=2, sticky=E)
+ self.etVersion = Label(root, textvariable=self.varVersion, anchor=W, relief=SUNKEN)
+ self.etVersion.grid(row=1, column=3, columnspan=4, padx=5, pady=5, sticky=W+E)
+
+ self.varPWMRes = StringVar()
+ Label(root, text="PWM Resolution:").grid(row=2, column=2, sticky=E)
+ self.etPWMRes = Label(root, textvariable=self.varPWMRes, anchor=W, relief=SUNKEN)
+ self.etPWMRes.grid(row=2, column=3, columnspan=4, padx=5, pady=5, sticky=W+E)
+
+ self.varPWMFreq = IntVar()
+ Label(root, text="PWM Frequency:").grid(row=3, column=2, sticky=E)
+ self.varPWMFreq.set(device_drv.MIN_PWM_FREQ)
+ self.scPWMFreq = Scale(root, length=250, from_=device_drv.MIN_PWM_FREQ, to=device_drv.MAX_PWM_FREQ, resolution=1, tickinterval=50, orient=HORIZONTAL, variable=self.varPWMFreq, command=self.cbSetPWMFreq)
+ self.scPWMFreq.grid(row=3, column=3, columnspan=4, padx=5, pady=5, sticky="W")
+
+ self.varCommonBright = IntVar()
+ Label(root, text="Common Brightness:").grid(row=4, column=2, sticky=E)
+ self.varCommonBright.set(0)
+ self.scCommonBright = Scale(root, length=250, from_=0, to=255, resolution=1, tickinterval=50, orient=HORIZONTAL, variable=self.varCommonBright, command=self.cbSetCommonBrightness)
+ self.scCommonBright.grid(row=4, column=3, columnspan=4, padx=5, pady=5, sticky=W)
+
+ self.btScanDevices = Button(root, text="Scan Devices", command=self.cbScanDevices)
+ self.btScanDevices.grid(row=5, column=0, padx=5, pady=5, ipadx=5)
+
+ self.btResetSetup = Button(root, text="Firmware update", command=self.cbFirmwareUpdate)
+ self.btResetSetup.grid(row=5, column=1, padx=5, pady=5, ipadx=5)
+
+ self.btStoreSetup = Button(root, text="Backup", command=self.cbBackupSetup)
+ self.btStoreSetup.grid(row=5, column=2, padx=5, pady=5, ipadx=5, sticky=E)
+
+ self.btStoreSetup = Button(root, text="Restore", command=self.cbRestoreSetup)
+ self.btStoreSetup.grid(row=5, column=3, padx=5, pady=5, ipadx=5, sticky=W)
+
+ self.btResetSetup = Button(root, text="Reset Setup", command=self.cbResetSetup)
+ self.btResetSetup.grid(row=5, column=4, padx=5, pady=5, ipadx=5, sticky=E)
+
+ self.btStoreSetup = Button(root, text="Store Setup", command=self.cbStoreSetup)
+ self.btStoreSetup.grid(row=5, column=5, padx=5, pady=5, ipadx=5, sticky=W)
+
+ self.varStatus = StringVar()
+ self.lbStatus = Label(root, textvariable=self.varStatus, anchor=W, relief=RIDGE)
+ self.lbStatus.grid(row=6, column=0, columnspan=6, padx=0, pady=0, sticky=W+E)
+
+
+ def cbSheetSelected(self, event):
+ if self.selectedConfig:
+ self.loadDeviceValues()
+
+ def cbFirmwareUpdate(self):
+ if len(device_drv.DeviceList):
+ self.firmwareUpdate()
+
+ def cbResetSetup(self):
+ if len(device_drv.ConfigMap):
+ self.resetSetup()
+ if self.selectedConfig:
+ self.loadDeviceValues()
+
+ def cbStoreSetup(self):
+ if len(device_drv.ConfigMap):
+ self.storeSetup()
+ if self.selectedConfig:
+ self.loadDeviceValues()
+
+ def cbBackupSetup(self):
+ if self.selectedConfig:
+ self.backupSetup()
+
+ def cbRestoreSetup(self):
+ if self.selectedConfig:
+ self.restoreSetup()
+
+ def cbSetCommonBrightness(self, val):
+ if self.selectedConfig:
+ try:
+ self.selectedConfig.setCommonBright(int(val))
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
+ def cbSetPWMFreq(self, val):
+ if self.selectedConfig:
+ try:
+ self.selectedConfig.setPWMFreq(int(val))
+ self.varPWMRes.set(self.selectedConfig.pwmRes)
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
+ def cbSelectDevice(self, event):
+ s = self.lbDevices.curselection()
+ if len(s) == 1:
+ self.selectDevice(int(s[0]))
+
+ def cbScanDevices(self):
+ self.scanDevices()
+
+ def scanDevices(self):
+ deviceList = None
+ self.selectedConfig = None
+ self.selectedDeviceIdx = -1
+ while not deviceList:
+ try:
+ device_drv.LoadConfigs()
+ if len(device_drv.DeviceList):
+ deviceList = device_drv.DeviceList
+ except (device_drv.AtmoControllerError, usb.USBError) as err:
+ if not tkMessageBox.askretrycancel(self.root.winfo_toplevel().title(), "Scanning for controllers fails:" + err.__str__(), icon=tkMessageBox.ERROR):
+ return False
+ else:
+ if not deviceList:
+ if not tkMessageBox.askretrycancel(self.root.winfo_toplevel().title(), "No Controllers found!", icon=tkMessageBox.ERROR):
+ return False
+
+ idList = ""
+ for dev in deviceList:
+ if len(idList) > 0:
+ idList = idList + " "
+ idList = idList + dev.id
+ self.varDeviceList.set(idList)
+
+ self.layoutDlg.setLayoutFromConfig()
+ self.selectDevice(0)
+ return True
+
+ def selectDevice(self, i):
+ self.selectedDeviceIdx = i
+ dev = device_drv.DeviceList[i]
+ id = dev.id
+ if id in device_drv.ConfigMap:
+ config = device_drv.ConfigMap[id]
+ if self.selectedConfig != config:
+ self.selectedConfig = config
+ self.scCommonBright.configure(to=self.selectedConfig.commonPWMRes)
+ self.loadDeviceValues()
+ else:
+ if dev.bootloader_mode():
+ s = "Bootloader USB:{0}".format(dev.version)
+ else:
+ s = "USB:{0} Bootloader PWM:{1:04X}".format(dev.version, dev.get_pwm_version())
+ self.varVersion.set(s)
+ self.lbDevices.selection_clear(0, END)
+ self.lbDevices.selection_set(i)
+ self.lbDevices.see(i)
+
+ def loadDeviceValues(self):
+ self.varVersion.set(self.selectedConfig.version)
+ self.varPWMRes.set(self.selectedConfig.pwmRes)
+ self.varPWMFreq.set(self.selectedConfig.pwmFreq)
+ self.varCommonBright.set(self.selectedConfig.commonBright)
+
+ def storeAndQuit(self, root):
+ if len(device_drv.ConfigMap):
+ if tkMessageBox.askokcancel(self.root.winfo_toplevel().title(), "Store Setup?", icon=tkMessageBox.QUESTION):
+ self.storeSetup()
+ self.resetDevices()
+ device_drv.ReleaseDevices()
+ root.quit()
+
+ def storeSetup(self):
+ self.layoutDlg.setConfigFromLayout()
+ try:
+ for id in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[id]
+ config.write()
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
+ def resetSetup(self):
+ if tkMessageBox.askokcancel(self.root.winfo_toplevel().title(), "Really reset setup of all controllers?", default="cancel", icon=tkMessageBox.QUESTION):
+ try:
+ for id in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[id]
+ config.reset()
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
+ def resetDevices(self):
+ try:
+ for id in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[id]
+ config.ctrl.reset_pwm_ctrl()
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
+ def backupSetup(self):
+ self.layoutDlg.setConfigFromLayout()
+ ctrl = self.selectedConfig.ctrl
+ initialfile = ctrl.id
+ initialfile = string.replace(initialfile, "[", "(")
+ initialfile = string.replace(initialfile, "]", ")")
+ initialfile = string.replace(initialfile, ",", "_")
+ initialfile = initialfile + ".dfc"
+ self.selectedConfig.ctrl = None
+ file = None
+ try:
+ file = tkFileDialog.asksaveasfile("w", title="Backup Configuration for " + self.selectedConfig.id, defaultextension=".dfc", filetypes=[ ("DF10CH Config", "*.dfc") ], initialfile=initialfile)
+ if file:
+ pickle.dump(self.selectedConfig, file)
+ except IOError:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), "Could not save configuration to file!")
+ finally:
+ self.selectedConfig.ctrl = ctrl
+ if file:
+ file.close()
+
+ def restoreSetup(self):
+ file = None
+ try:
+ file = tkFileDialog.askopenfile("r", title="Restore Configuration for " + self.selectedConfig.id, defaultextension=".dfc", filetypes=[ ("DF10CH Config", "*.dfc") ])
+ if file:
+ config = pickle.load(file)
+ else:
+ return
+ except IOError:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), "Could not read configuration from file!")
+ return
+ finally:
+ if file:
+ file.close()
+
+ config.id = self.selectedConfig.id
+ config.ctrl = self.selectedConfig.ctrl
+
+ try:
+ config.ctrl.set_common_brightness(config.commonBright)
+ config.ctrl.set_pwm_freq(config.pwmFreq)
+ config.write()
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
+ device_drv.ConfigMap[config.id] = config
+ self.selectedConfig = config
+ self.layoutDlg.setLayoutFromConfig()
+ self.scCommonBright.configure(to=self.selectedConfig.commonPWMRes)
+ self.loadDeviceValues()
+
+ def firmwareUpdate(self):
+ try:
+ filename = tkFileDialog.askopenfilename(title="Select firmware", defaultextension=".dff", filetypes=[ ("DF10CH Firmware", "*.dff") ])
+ if not filename or len(filename) == 0:
+ return
+ fw = firmware.FlashMem(filename, 64, True)
+ except (IOError, firmware.FirmwareFlashError) as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ return
+
+ target = fw.target
+ if target != "DF10CH-USB" and target != "DF10CH-PWM":
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), "Unknown firmware target '{0}'!".format(target))
+ return
+
+ if target == "DF10CH-PWM":
+ for ctrl in device_drv.DeviceList:
+ if ctrl.bootloader_mode():
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), "{0}: Firmware of USB controller must be installed first!".format(ctrl.id))
+ return
+
+ if not tkMessageBox.askokcancel(self.root.winfo_toplevel().title(), "Target controller: {0}, Firmware version: {1}. Really start firmware update?".format(target, fw.version), default="cancel", icon=tkMessageBox.QUESTION):
+ return
+
+ self.displayStatus("Start bootloaders...")
+
+ doFlash = True
+ doRefresh = False
+ try:
+ for ctrl in device_drv.DeviceList:
+ if target == "DF10CH-USB":
+ if not ctrl.bootloader_mode():
+ doRefresh = True
+ ctrl.start_bootloader()
+ else:
+ if not ctrl.get_pwm_bootloader_mode():
+ ctrl.start_pwm_ctrl_bootloader()
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ doFlash = False
+
+ if doRefresh:
+ time.sleep(5.0)
+ try:
+ device_drv.FindDevices()
+ except (device_drv.AtmoControllerError, usb.USBError) as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ doFlash = False
+
+ for ctrl in device_drv.DeviceList:
+ try:
+ if target == "DF10CH-USB":
+ if ctrl.bootloader_mode():
+ if doFlash:
+ pageSize = ctrl.get_flash_page_size()
+ if pageSize != fw.pageSize:
+ fw = firmware.FlashMem(filename, pageSize)
+ firstPage = fw.getPageForAddr(0x0000)
+ i = 1
+ if firstPage:
+ fp = firmware.FlashPage(0x0000, pageSize)
+ ctrl.write_flash_page(fp.baseAddr, fp.data)
+ i = 2
+ n = len(fw.pageList)
+ for fp in fw.pageList:
+ if fp != firstPage:
+ self.displayStatus("Flashing USB controller {0}: {1}%".format(ctrl.id, i * 100 / n))
+ ctrl.write_flash_page(fp.baseAddr, fp.data)
+ i = i + 1
+ if firstPage:
+ ctrl.write_flash_page(firstPage.baseAddr, firstPage.data)
+ time.sleep(1.0)
+
+ i = 1
+ for fp in fw.pageList:
+ self.displayStatus("Verifying USB controller {0}: {1}%".format(ctrl.id, i * 100 / n))
+ data = ctrl.read_flash(fp.baseAddr, fp.pageSize)
+ fp.verify(data)
+ i = i + 1
+ time.sleep(1.0)
+ else:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), "{0}: Bootloader of USB controller does not start!".format(ctrl.id))
+ doFlash = False
+ else:
+ if ctrl.get_pwm_bootloader_mode():
+ if doFlash:
+ pageSize = ctrl.get_pwm_flash_page_size()
+ if pageSize != fw.pageSize:
+ fw = firmware.FlashMem(filename, pageSize)
+ firstPage = fw.getPageForAddr(0x0000)
+ i = 1
+ if firstPage:
+ fp = firmware.FlashPage(0x0000, pageSize)
+ ctrl.write_pwm_flash_page(fp.baseAddr, fp.data)
+ i = 2
+ n = len(fw.pageList)
+ for fp in fw.pageList:
+ if fp != firstPage:
+ self.displayStatus("Flashing PWM controller {0}: {1}%".format(ctrl.id, i * 100 / n))
+ ctrl.write_pwm_flash_page(fp.baseAddr, fp.data)
+ i = i + 1
+ if firstPage:
+ ctrl.write_pwm_flash_page(firstPage.baseAddr, firstPage.data)
+ time.sleep(1.0)
+
+ i = 1
+ for fp in fw.pageList:
+ self.displayStatus("Verifying PWM controller {0}: {1}%".format(ctrl.id, i * 100 / n))
+ data = ctrl.read_pwm_flash(fp.baseAddr, fp.pageSize)
+ fp.verify(data)
+ i = i + 1
+ time.sleep(1.0)
+ else:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), "{0}: Bootloader of PWM controller does not start!".format(ctrl.id))
+ doFlash = False
+ except (device_drv.AtmoControllerError, firmware.FirmwareFlashError) as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ doFlash = False
+
+ doRefresh = False
+ for ctrl in device_drv.DeviceList:
+ try:
+ if target == "DF10CH-USB":
+ if ctrl.bootloader_mode():
+ doRefresh = True
+ ctrl.start_appl()
+ else:
+ if ctrl.get_pwm_bootloader_mode():
+ ctrl.reset_pwm_ctrl()
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+
+ if doRefresh:
+ self.displayStatus("Start firmware...")
+ time.sleep(5.0)
+ self.displayStatus("")
+ self.scanDevices()
+
+ def displayStatus(self, msg):
+ self.varStatus.set(msg)
+ self.root.update_idletasks()
diff --git a/df10ch_setup_pkg/device_drv.py b/df10ch_setup_pkg/device_drv.py
new file mode 100644
index 0000000..cf00272
--- /dev/null
+++ b/df10ch_setup_pkg/device_drv.py
@@ -0,0 +1,1011 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+import os
+import usb
+import time
+import pickle
+import string
+
+# ---
+# Communication protocol related defines for 10 channel RGB Controller.
+#
+VENDOR_ID = 0x16c0
+PRODUCT_ID = 0x05dc
+VENDOR_NAME = 'yak54@gmx.net'
+DEVICE_NAME = 'DF10CH'
+
+REQ_USB_START = 0 # Start of usb controller requests
+REQ_USB_BL_START = 64 # Start of usb controller boot loader requests
+REQ_PWM_START = 128 # Start of pwm controller requests
+REQ_PWM_BL_START = 192 # Start of pwm controller bootloader requests
+
+ # usb controller requests
+for i, key in enumerate([
+ 'REQ_START_BOOTLOADER', # start boot loader of usb controller
+
+ 'REQ_READ_EE_DATA', # read eeprom data (wLength: number of bytes, wIndex: eeprom start address)
+ 'REQ_WRITE_EE_DATA', # write eeprom data (wLength: number of bytes, wIndex: eeprom start address)
+
+ 'REQ_STOP_PWM_CTRL', # stop PWM controller
+ 'REQ_RESET_PWM_CTRL', # reset PWM controller
+ 'REQ_BOOTLOADER_RESET_PWM_CTRL', # reset PWM controller and signal bootloader start
+
+ 'REQ_SET_REPLY_TIMEOUT', # set reply timeout values (wValue: start timeout [ms], wIndex: timeout [ms])
+ 'REQ_GET_REPLY_ERR_STATUS' # get reply error status (COMM_ERR_...)
+ ], start = REQ_USB_START):
+ exec key + ' = ' + repr(i)
+
+ # usb controller boot loader requests
+for i, key in enumerate([
+ 'BL_REQ_WRITE_PAGE', # write flash page
+ 'BL_REQ_LEAVE_BOOT', # leave boot loader and start application
+ 'BL_REQ_GET_PAGE_SIZE', # return flash page size of device
+ 'BL_REQ_READ_FLASH' # read flash memory
+ ], start = REQ_USB_BL_START):
+ exec key + ' = ' + repr(i)
+
+ # pwm controller requests
+for i, key in enumerate([
+ 'PWM_REQ_GET_VERSION', # Get firmware version
+
+ 'PWM_REQ_SET_BRIGHTNESS', # Set channel brightness values (wLenght: number of bytes, wIndex: start channel)
+ 'PWM_REQ_SET_BRIGHTNESS_SYNCED',
+ 'PWM_REQ_GET_BRIGHTNESS',
+
+ 'PWM_REQ_SET_CHANNEL_MAP', # Set channel to port mapping (wLength: number of bytes, wIndex: start channel)
+ 'PWM_REQ_GET_CHANNEL_MAP',
+
+ 'PWM_REQ_SET_COMMON_PWM', # Set common pwm value (wValue.low: pwm value)
+ 'PWM_REQ_GET_COMMON_PWM',
+
+ 'PWM_REQ_STORE_SETUP', # Store actual calibration values
+ 'PWM_REQ_RESET_SETUP', # Reset calibration values to default
+
+ 'PWM_REQ_GET_REQUEST_ERR_STATUS', # Get request error status (COMM_ERR_...)
+
+ 'PWM_REQ_GET_MAX_PWM', # Get maximum internal PWM value
+
+ 'PWM_REQ_SET_PWM_FREQ',
+ 'PWM_REQ_GET_PWM_FREQ',
+
+ 'PWM_REQ_ECHO_TEST' ## Reply 8 byte header
+ ], start = REQ_PWM_START):
+ exec key + '=' + repr(i)
+
+ # pwm controller boot loader requests
+for i, key in enumerate([
+ 'BL_PWM_REQ_WRITE_PAGE', # write flash page
+ 'BL_PWM_REQ_GET_PAGE_SIZE', # return flash page size of device
+ 'BL_PWM_REQ_READ_FLASH', # read flash memory
+ 'BL_PWM_REQ_GET_REQUEST_ERR_STATUS', # Get request error status (COMM_ERR_...)
+ ], start = REQ_PWM_BL_START):
+ exec key + ' = ' + repr(i)
+
+ # Data payload related
+MAX_PWM_REQ_PAYLOAD_SIZE = 128
+MAX_PWM_REPLY_PAYLOAD_SIZE = 128
+
+# Error flag definition for communication error's between usb and pwm controller
+COMM_ERR_OVERRUN = 0
+COMM_ERR_FRAME = 1
+COMM_ERR_TIMEOUT = 2
+COMM_ERR_START = 3
+COMM_ERR_OVERFLOW = 4
+COMM_ERR_CRC = 5
+COMM_ERR_DUPLICATE = 6
+COMM_ERR_DEBUG = 7
+
+# Port channel mapping related
+NCHANNELS = 30 # Number of supported Channels
+
+NPORTS = 4
+PA_IDX = 0
+PB_IDX = 1
+PC_IDX = 2
+PD_IDX = 3
+
+def CM_CODE(port, channel):
+ return(((channel) << 2) | (port))
+def CM_CHANNEL(code):
+ return((code) >> 2)
+def CM_PORT(code):
+ return((code) & 0x03)
+def CM_BV(bit):
+ return (1<<bit)
+def CM_BIT(bv):
+ i = 0
+ while bv:
+ i = i + 1
+ bv = bv >> 1
+ return i - 1
+
+
+PORT_NAME_MAP = {
+ # J3
+" 1.1": ( PA_IDX, CM_BV(2) ),
+" 1.2": ( PA_IDX, CM_BV(1) ),
+" 1.3": ( PA_IDX, CM_BV(0) ),
+
+ # J4
+" 2.1": ( PA_IDX, CM_BV(5) ),
+" 2.2": ( PA_IDX, CM_BV(4) ),
+" 2.3": ( PA_IDX, CM_BV(3) ),
+
+ # J5
+" 3.1": ( PC_IDX, CM_BV(7) ),
+" 3.2": ( PA_IDX, CM_BV(7) ),
+" 3.3": ( PA_IDX, CM_BV(6) ),
+
+ # J6
+" 4.1": ( PC_IDX, CM_BV(4) ),
+" 4.2": ( PC_IDX, CM_BV(5) ),
+" 4.3": ( PC_IDX, CM_BV(6) ),
+
+ # J7
+" 5.1": ( PC_IDX, CM_BV(1) ),
+" 5.2": ( PC_IDX, CM_BV(2) ),
+" 5.3": ( PC_IDX, CM_BV(3) ),
+
+ # J8
+" 6.1": ( PD_IDX, CM_BV(6) ),
+" 6.2": ( PD_IDX, CM_BV(7) ),
+" 6.3": ( PC_IDX, CM_BV(0) ),
+
+ # J9
+" 7.1": ( PD_IDX, CM_BV(3) ),
+" 7.2": ( PD_IDX, CM_BV(4) ),
+" 7.3": ( PD_IDX, CM_BV(5) ),
+
+ # J10
+" 8.1": ( PB_IDX, CM_BV(6) ),
+" 8.2": ( PB_IDX, CM_BV(7) ),
+" 8.3": ( PD_IDX, CM_BV(2) ),
+
+ # J11
+" 9.1": ( PB_IDX, CM_BV(3) ),
+" 9.2": ( PB_IDX, CM_BV(4) ),
+" 9.3": ( PB_IDX, CM_BV(5) ),
+
+ # J12
+"10.1": ( PB_IDX, CM_BV(0) ),
+"10.2": ( PB_IDX, CM_BV(1) ),
+"10.3": ( PB_IDX, CM_BV(2) )
+}
+
+# Brightness related
+NBRIGHTS = 256
+NCOMMONBRIGHTS = 256
+
+# PWM frequency related
+MIN_PWM_FREQ = 50
+MAX_PWM_FREQ = 400
+
+# PWM controller version request related
+PWM_VERS_APPL = 0 # Is application firmware
+PWM_VERS_BOOT = 1 # Is bootloader firmware
+
+# USB related
+DEF_USB_TIMEOUT = 100
+DEF_RETRY = 3
+
+def GetCommErrMsg(stat):
+ if stat == 0:
+ rc = 'OK'
+ else:
+ rc = ''
+ if stat & (1<<COMM_ERR_OVERRUN):
+ rc = rc + " OVERRUN"
+ if stat & (1<<COMM_ERR_FRAME):
+ rc = rc + " FRAME"
+ if stat & (1<<COMM_ERR_TIMEOUT):
+ rc = rc + " TIMEOUT"
+ if stat & (1<<COMM_ERR_START):
+ rc = rc + " START"
+ if stat & (1<<COMM_ERR_OVERFLOW):
+ rc = rc + " OVERFLOW"
+ if stat & (1<<COMM_ERR_CRC):
+ rc = rc + " CRC"
+ if stat & (1<<COMM_ERR_DUPLICATE):
+ rc = rc + " DUPLICATE"
+ if stat & (1<<COMM_ERR_DEBUG):
+ rc = rc + " DEBUG"
+ return rc
+
+
+CONFIG_VALID_ID = 0xA0A1
+CONFIG_VERSION = 0x0001
+CONFIG_CLASS_VERSION = 0x0001
+
+DEFAULT_GAMMA_VAL = 22
+MIN_GAMMA_VAL = 10
+MAX_GAMMA_VAL = 50
+
+AREA_NAMES = "Top", "Bottom", "Left", "Right", "Center", "TopLeft", "TopRight", "BottomLeft", "BottomRight"
+MAX_AREAS = 30, 30, 30, 30, 1, 1, 1, 1, 1
+
+def NumBaseAreas():
+ return len(AREA_NAMES)
+
+def AreaIndex(area):
+ return AREA_NAMES.index(area)
+
+def AreaName(code, areaNum):
+ areaIdx = code >> 2
+ if areaIdx < 4:
+ return "{0}-{1}".format(AREA_NAMES[areaIdx], areaNum + 1)
+ if areaIdx < NumBaseAreas():
+ return AREA_NAMES[areaIdx]
+ return None
+
+COLOR_NAMES = "red", "green", "blue"
+
+def ColorIndex(name):
+ return COLOR_NAMES.index(name)
+
+def ColorName(code):
+ return COLOR_NAMES[code & 0x03]
+
+def AreaCode(area, color):
+ s = string.split(area, '-')
+ areaIdx = AreaIndex(s[0])
+ if areaIdx < 4:
+ areaNum = int(s[1]) - 1
+ else:
+ areaNum = 0
+ return ((areaIdx << 2) + (color & 0x03)), areaNum
+
+
+class AtmoControllerError(Exception):
+ def __init__(self, dev, msg):
+ self.id = dev.id
+ self.message = msg
+
+ def __str__(self):
+ return '{0}: {1}'.format(self.id, self.message)
+
+
+
+class DF10CHController:
+ '''
+ Interface to DF10CH RGB Controller
+ '''
+
+ def __init__(self, usbdev, busnum, devnum, version, serial):
+ self.usbdev = usbdev
+ self.busnum = busnum
+ self.devnum = devnum
+ self.version = version
+ self.serial = serial
+ self.id = 'DF10CH[{0},{1}]'.format(self.busnum, self.devnum)
+
+ def release(self):
+ self.usbdev.releaseInterface()
+
+ def bootloader_mode(self):
+ return self.serial == "BL"
+
+ def ctrl_write(self, req, value, index, data, timeout = DEF_USB_TIMEOUT, retry = DEF_RETRY):
+ while retry > 0:
+ try:
+ retry = retry - 1
+ written = self.usbdev.controlMsg(usb.ENDPOINT_OUT|usb.RECIP_DEVICE|usb.TYPE_VENDOR, req, data, value, index, timeout)
+ except usb.USBError as err:
+ if retry == 0:
+ raise AtmoControllerError(self, err.__str__())
+ else:
+ if written != len(data):
+ raise AtmoControllerError(self, 'could not write all payload data to device')
+ break
+
+ def ctrl_read(self, req, value = 0, index = 0, size = 0, timeout = DEF_USB_TIMEOUT, retry = DEF_RETRY):
+ while retry > 0:
+ try:
+ retry = retry - 1
+ data = self.usbdev.controlMsg(usb.ENDPOINT_IN|usb.RECIP_DEVICE|usb.TYPE_VENDOR, req, size, value, index, timeout)
+ except usb.USBError as err:
+ if retry == 0:
+ raise AtmoControllerError(self, err.__str__())
+ else:
+ if len(data) != size:
+ raise AtmoControllerError(self, 'could not read all payload data')
+ break
+ return data
+
+ def pwm_ctrl_write(self, req, value, index, data, timeout = DEF_USB_TIMEOUT, retry = DEF_RETRY):
+ if len(data) > MAX_PWM_REQ_PAYLOAD_SIZE:
+ raise AtmoControllerError(self, 'to many bytes in payload request data')
+ self.ctrl_write(req, value, index, data, timeout, retry)
+
+ def pwm_ctrl_read(self, req, value = 0, index = 0, size = 0, timeout = DEF_USB_TIMEOUT, retry = DEF_RETRY):
+ if size > MAX_PWM_REPLY_PAYLOAD_SIZE:
+ raise AtmoControllerError(self, 'to many bytes for reply payload data')
+ return self.ctrl_read(req, value, index, size, timeout, retry)
+
+ def verify_reply_data(self, start, data, rdata, msg):
+ for i in range(len(data)):
+ if data[i] != rdata[i]:
+ raise AtmoControllerError(self, '{4}: verify of written {3} data fails {0:04X}: write {1:02X} read {2:02X}'.format(start + i, data[i], rdata[i], msg, self.id))
+
+ def read_ee_data(self, start, size):
+ return self.ctrl_read(REQ_READ_EE_DATA, 0, start, size)
+
+ def write_ee_data(self, start, data):
+ self.ctrl_write(REQ_WRITE_EE_DATA, 0, start, data, DEF_USB_TIMEOUT + len(data) * 10)
+ eedata = self.read_ee_data(start, len(data))
+ self.verify_reply_data(start, data, eedata, 'eeprom')
+
+ def stop_pwm_ctrl(self):
+ self.ctrl_read(REQ_STOP_PWM_CTRL)
+
+ def reset_pwm_ctrl(self):
+ self.ctrl_read(REQ_RESET_PWM_CTRL)
+
+ def start_pwm_ctrl_bootloader(self):
+ self.ctrl_read(REQ_BOOTLOADER_RESET_PWM_CTRL)
+
+ def set_reply_timeout(self, start_timeout, timeout):
+ self.ctrl_read(REQ_SET_REPLY_TIMEOUT, start_timeout, timeout)
+
+ def get_reply_error_status(self):
+ data = self.ctrl_read(REQ_GET_REPLY_ERR_STATUS, 0, 0, 1)
+ return data[0]
+
+ def start_bootloader(self):
+ self.ctrl_read(REQ_START_BOOTLOADER)
+
+ def start_appl(self):
+ self.ctrl_read(BL_REQ_LEAVE_BOOT)
+
+ def get_flash_page_size(self):
+ data = self.ctrl_read(BL_REQ_GET_PAGE_SIZE, 0, 0, 2)
+ return data[0] + data[1] * 256
+
+ def write_flash_page(self, addr, data):
+ self.ctrl_write(BL_REQ_WRITE_PAGE, 0, addr, data)
+
+ def read_flash(self, addr, len):
+ return self.ctrl_read(BL_REQ_READ_FLASH, 0, addr, len)
+
+ def get_request_error_status(self):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_REQUEST_ERR_STATUS, 0, 0, 1)
+ return data[0]
+
+ def set_brightness(self, start, values):
+ data = list();
+ for i in range(len(values)):
+ data.append(values[i] & 0x00FF)
+ data.append(values[i] / 256)
+ self.pwm_ctrl_write(PWM_REQ_SET_BRIGHTNESS, 0, start, data)
+
+ def set_brightness_synced(self, start, values):
+ data = list();
+ for i in range(len(values)):
+ data.append(values[i] & 0x00FF)
+ data.append(values[i] / 256)
+ self.pwm_ctrl_write(PWM_REQ_SET_BRIGHTNESS_SYNCED, 0, start, data)
+
+ def get_brightness(self, start, nch):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_BRIGHTNESS, 0, start, nch * 2)
+ values = list()
+ for i in range(nch):
+ values.append(data[i*2] + data[i*2+1] * 256)
+ return values;
+
+ def get_channel_map(self, start, nch):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_CHANNEL_MAP, 0, start, nch * 2)
+ map = list()
+ for i in range(nch):
+ map.append(dict(channel=CM_CHANNEL(data[i*2]), port=CM_PORT(data[i*2]), pins=data[i*2+1]))
+ return map;
+
+ def set_channel_map(self, start, map):
+ data = list()
+ for mapRec in map:
+ data.append(CM_CODE(mapRec['port'], mapRec['channel']))
+ data.append(mapRec['pins'])
+ self.pwm_ctrl_write(PWM_REQ_SET_CHANNEL_MAP, 0, start, data)
+
+ def set_common_brightness(self, value):
+ self.pwm_ctrl_read(PWM_REQ_SET_COMMON_PWM, value)
+
+ def get_common_brightness(self):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_COMMON_PWM, 0, 0, 2)
+ return data[0] + data[1] * 256;
+
+ def get_max_pwm_value(self):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_MAX_PWM, 0, 0, 4)
+ return data[0] + 256 * data[1]
+
+ def get_common_max_pwm_value(self):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_MAX_PWM, 0, 0, 4)
+ return data[2] + 256 * data[3]
+
+ def set_pwm_freq(self, value):
+ self.pwm_ctrl_read(PWM_REQ_SET_PWM_FREQ, value)
+
+ def get_pwm_freq(self):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_PWM_FREQ, 0, 0, 2)
+ return data[0] + 256 * data[1]
+
+ def store_setup(self):
+ self.pwm_ctrl_read(PWM_REQ_STORE_SETUP, 0, 0, 0, 1500)
+
+ def reset_setup(self):
+ self.pwm_ctrl_read(PWM_REQ_RESET_SETUP)
+
+ def get_pwm_bootloader_mode(self):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_VERSION, 0, 0, 2)
+ return (data[0] == PWM_VERS_BOOT)
+
+ def get_pwm_version(self):
+ data = self.pwm_ctrl_read(PWM_REQ_GET_VERSION, 0, 0, 2)
+ return data[1]
+
+ def get_pwm_flash_page_size(self):
+ data = self.pwm_ctrl_read(BL_PWM_REQ_GET_PAGE_SIZE, 0, 0, 2)
+ return data[0] + data[1] * 256
+
+ def write_pwm_flash_page(self, addr, data):
+ self.pwm_ctrl_write(BL_PWM_REQ_WRITE_PAGE, 0, addr, data)
+
+ def read_pwm_flash(self, addr, len):
+ return self.pwm_ctrl_read(BL_PWM_REQ_READ_FLASH, 0, addr, len)
+
+ def get_bootloader_request_error_status(self):
+ data = self.pwm_ctrl_read(BL_PWM_REQ_GET_REQUEST_ERR_STATUS, 0, 0, 1)
+ return data[0]
+
+
+dummySerial = "AP"
+
+class dummyController:
+ def __init__(self, busnum, devnum):
+ self.busnum = busnum
+ self.devnum = devnum
+ self.serial = dummySerial
+ self.id = 'DUMMY[{0},{1}]'.format(self.busnum, self.devnum)
+ self.version = 0x0101
+ self.ee_data = [ 0xFF ] * 512
+ self._reset_setup()
+ self.start_timeout = 50
+ self.timeout = 10
+ self.bright = [ 0] * NCHANNELS
+ self.flash = dict()
+ self.pwm_vers = PWM_VERS_APPL
+ self.pwm_flash = dict()
+
+ def _reset_setup(self):
+ self.common_bright = NCOMMONBRIGHTS - 1
+ self.pwm_freq = 100
+ self.max_pwm = int(16000000 / (16 * 9 * self.pwm_freq) - 1);
+ self.ch_map = [ dict(channel=0, port=0, pins=0) ] * 30
+
+ def release(self):
+ print "{0}: release interface".format(self.id)
+
+ def bootloader_mode(self):
+ return self.serial == "BL"
+
+ def read_ee_data(self, start, size):
+ return self.ee_data[start: start + size]
+
+ def write_ee_data(self, start, data):
+ self.ee_data[start: start + len(data)] = data
+ print "{0}: set ee data:".format(self.id), self.ee_data
+
+ def stop_pwm_ctrl(self):
+ self.pwm_vers = PWM_VERS_APPL
+ print "{0}: stop pwm controller".format(self.id)
+
+ def reset_pwm_ctrl(self):
+ self.pwm_vers = PWM_VERS_APPL
+ print "{0}: reset pwm controller".format(self.id)
+
+ def start_pwm_ctrl_bootloader(self):
+ self.pwm_vers = PWM_VERS_BOOT
+ print "{0}: start pwm controller bootloader".format(self.id)
+
+ def set_reply_timeout(self, start_timeout, timeout):
+ self.start_timeout = start_timeout
+ self.timeout = timeout
+ print "{0}: set start_timeout {1} timeout {2}".format(self.id, start_timeout, timeout)
+
+ def get_reply_error_status(self):
+ return 0
+
+ def start_bootloader(self):
+ print "start bootloader"
+ global dummySerial
+ dummySerial = "BL"
+
+ def start_appl(self):
+ print "start appl"
+ global dummySerial
+ dummySerial = "AP"
+
+ def get_flash_page_size(self):
+ return 64
+
+ def write_flash_page(self, addr, data):
+ print "write flash page {0:04X}: {1}".format(addr, data)
+ self.flash[addr] = data
+
+ def read_flash(self, addr, len):
+ if not addr in self.flash:
+ self.flash[addr] = [ 255 ] * len
+ return self.flash[addr]
+
+ def get_request_error_status(self):
+ return 0
+
+ def set_brightness(self, start, values):
+ self.bright[start: start + len(values)] = values
+ print "{0}: set bright:".format(self.id), self.bright
+
+ def set_brightness_synced(self, start, values):
+ self.bright[start: start + len(values)] = values
+ print "{0}: set bright synced:".format(self.id), self.bright
+
+ def get_brightness(self, start, nch):
+ return self.bright[start: start + nch]
+
+ def get_channel_map(self, start, nch):
+ return self.ch_map[start: start + nch]
+
+ def set_channel_map(self, start, map):
+ self.ch_map[start: start + len(map)] = map
+ print "{0}: set channel map:".format(self.id), self.ch_map
+
+ def set_common_brightness(self, value):
+ self.common_bright = value
+ print "{0}: set common brightness:".format(self.id), self.common_bright
+
+ def get_common_brightness(self):
+ return self.common_bright
+
+ def get_max_pwm_value(self):
+ return self.max_pwm
+
+ def get_common_max_pwm_value(self):
+ return NCOMMONBRIGHTS - 1
+
+ def set_pwm_freq(self, value):
+ self.pwm_freq = value
+ self.max_pwm = int(16000000 / (16 * 9 * value) - 1);
+ print "{0}: set pwm freq {1} max pwm {2}".format(self.id, self.pwm_freq, self.max_pwm)
+
+ def get_pwm_freq(self):
+ return self.pwm_freq
+
+ def store_setup(self):
+ global dummyDevices
+ file = open("dummyctrls.objs", "w")
+ pickle.dump(dummyDevices, file)
+ file.close()
+ print "{0}: store setup".format(self.id)
+
+ def reset_setup(self):
+ self._reset_setup()
+ global dummyDevices
+ file = open("dummyctrls.objs", "w")
+ pickle.dump(dummyDevices, file)
+ file.close()
+ print "{0}: reset setup".format(self.id)
+
+ def get_pwm_bootloader_mode(self):
+ return self.pwm_vers == PWM_VERS_BOOT
+
+ def get_pwm_version(self):
+ return 1
+
+ def get_bootloader_request_error_status(self):
+ return 0
+
+ def get_pwm_flash_page_size(self):
+ return 128
+
+ def write_pwm_flash_page(self, addr, data):
+ print "write pwm flash page {0:04X}: {1}".format(addr, data)
+ self.pwm_flash[addr] = data
+
+ def read_pwm_flash(self, addr, len):
+ if not addr in self.pwm_flash:
+ self.pwm_flash[addr] = [ 255 ] * len
+ return self.pwm_flash[addr]
+
+
+dummyDevices = None
+SimulatedControllers = 0
+
+def loadDummyDevices():
+ global dummyDevices
+ try:
+ file = open("dummyctrls.objs", "r")
+ dummyDevices = pickle.load(file)
+ file.close()
+ except IOError:
+ dummyDevices = list()
+
+ if len(dummyDevices) > SimulatedControllers:
+ dummyDevices[SimulatedControllers: len(dummyDevices)] = []
+ while len(dummyDevices) < SimulatedControllers:
+ dummyDevices.append(dummyController(0, len(dummyDevices) + 1))
+
+ return dummyDevices
+
+
+class ControllerConfig:
+
+ def __init__(self, ctrl):
+ self.classVersion = CONFIG_CLASS_VERSION
+ self.ctrl = ctrl
+ self.id = ctrl.id
+ self.read()
+
+ def read(self):
+ self.ctrl.reset_pwm_ctrl()
+ self.pwmRes = self.ctrl.get_max_pwm_value()
+ self.commonPWMRes = self.ctrl.get_common_max_pwm_value()
+ self.pwmFreq = self.ctrl.get_pwm_freq()
+ self.commonBright = self.ctrl.get_common_brightness()
+ self.numAreas = [ 0 ] * NumBaseAreas()
+
+ eedata = self.ctrl.read_ee_data(1, 5 + len(self.numAreas) + NCHANNELS * 6)
+ #print "read eedata:", eedata
+ configValidId = eedata[0] + eedata[1] * 256
+ if configValidId == CONFIG_VALID_ID:
+ configVersion = "{0:04X}".format(eedata[2] + eedata[3] * 256)
+ for p in range(len(self.numAreas)):
+ self.numAreas[p] = eedata[4 + p]
+ if self.numAreas[p] > MAX_AREAS[p]: self.numAreas = MAX_AREAS[p]
+ else:
+ configVersion = ""
+ self.version = "USB:{0} PWM:{1:04X} CONFIG:{2}".format(self.ctrl.version, self.ctrl.get_pwm_version(), configVersion)
+ pwmChannelMap = self.ctrl.get_channel_map(0, NCHANNELS)
+ #print "read pwmChannelMap", pwmChannelMap
+ self.channelMap = dict()
+ self.numReqChannels = 0
+ for portName in PORT_NAME_MAP.keys():
+ foundArea = None
+ port, pin = PORT_NAME_MAP[portName]
+ for channelRec in pwmChannelMap:
+ reqChannel = channelRec['channel']
+ outPort = channelRec['port']
+ outPins = channelRec['pins']
+ if outPort == port and (outPins & pin):
+ if configValidId == CONFIG_VALID_ID:
+ p = 4 + len(self.numAreas)
+ self.numReqChannels = eedata[p]
+ if self.numReqChannels > NCHANNELS: self.numReqChannels = 0
+ p = p + 1
+ for i in range(self.numReqChannels):
+ if eedata[p] == reqChannel:
+ area = AreaName(eedata[p + 1], eedata[p + 2])
+ if area:
+ foundArea = area
+ color = eedata[p + 1] & 0x03
+ gamma = eedata[p + 3]
+ if gamma < MIN_GAMMA_VAL: gamma = MIN_GAMMA_VAL
+ if gamma > MAX_GAMMA_VAL: gamma = MAX_GAMMA_VAL
+ whiteCal = eedata[p + 4] + eedata[p + 5] * 256
+ if whiteCal > self.pwmRes: whiteCal = self.pwmRes
+ break
+ p = p + 6
+ break
+ if foundArea:
+ self.channelMap[portName] = dict(area=foundArea, color=color, gamma=gamma, whiteCal=whiteCal)
+ else:
+ self.channelMap[portName] = None
+ #print "read channelMap:", self.channelMap
+
+ def write(self):
+ #print "write channelMap:", self.channelMap
+ eedata = list()
+ eedata.append(CONFIG_VALID_ID & 0x00FF)
+ eedata.append(CONFIG_VALID_ID >> 8)
+ eedata.append(CONFIG_VERSION & 0x00FF)
+ eedata.append(CONFIG_VERSION >> 8)
+ eedata.extend(self.numAreas)
+ eedata.append(0)
+
+ reqChannelMap = dict()
+ pwmChannelMap = list()
+ n = 0
+ for portName in self.channelMap.keys():
+ port, pin = PORT_NAME_MAP[portName]
+ channelRec = self.channelMap[portName]
+ if channelRec:
+ area = channelRec['area']
+ color = channelRec['color']
+ whiteCal = channelRec['whiteCal']
+ if whiteCal > self.pwmRes: whiteCal = self.pwmRes
+ gamma = channelRec['gamma']
+ areaCode, areaNum = AreaCode(area, color)
+ key = '{0}{1}{2}{3}'.format(areaCode, areaNum, gamma, whiteCal)
+ if key in reqChannelMap:
+ reqChannel = reqChannelMap[key]
+ else:
+ reqChannel = n
+ n = n + 1
+ reqChannelMap[key] = reqChannel
+ eedata.append(reqChannel)
+ eedata.append(areaCode)
+ eedata.append(areaNum)
+ eedata.append(gamma)
+ eedata.append(whiteCal & 0x00FF)
+ eedata.append(whiteCal >> 8)
+ pwmChannelMap.append(dict(channel=reqChannel, port=port, pins=pin))
+
+ eedata[4 + len(self.numAreas)] = n
+
+ self.numReqChannels = 0
+ while len(pwmChannelMap) < NCHANNELS:
+ pwmChannelMap.append(dict(channel=0, port=0, pins=0))
+
+ #print "write pwmChannelMap:", pwmChannelMap
+ #print "write eedata:", eedata
+ self.ctrl.write_ee_data(1, eedata)
+ self.ctrl.set_channel_map(0, pwmChannelMap)
+ self.ctrl.store_setup()
+ self.read()
+
+ def reset(self):
+ self.ctrl.write_ee_data(1, [ 0xFF, 0xFF ])
+ self.ctrl.reset_setup()
+ self.read()
+
+ def setCommonBright(self, v):
+ if self.commonBright != v:
+ self.ctrl.set_common_brightness(v)
+ self.commonBright = v
+
+ def setPWMFreq(self, v):
+ if self.pwmFreq != v:
+ self.ctrl.set_pwm_freq(v)
+ self.pwmRes = self.ctrl.get_max_pwm_value()
+ self.pwmFreq = v
+
+
+DeviceList = list()
+
+def FindDevices():
+ global DeviceList
+
+ ReleaseDevices()
+
+ if SimulatedControllers:
+ DeviceList = loadDummyDevices()
+ return
+
+ busses = usb.busses()
+ busnum = 0
+ for bus in busses:
+ devnum = 0
+ for dev in bus.devices:
+ if dev.idProduct == PRODUCT_ID and dev.idVendor == VENDOR_ID:
+ try:
+ handle = dev.open()
+ if handle.getString(dev.iManufacturer, 64) == VENDOR_NAME and handle.getString(dev.iProduct, 64) == DEVICE_NAME:
+ handle.setConfiguration(1)
+ handle.claimInterface(0)
+ serial = handle.getString(dev.iSerialNumber, 64)
+ if os.name == "nt":
+ bn = bus.location
+ dn = dev.devnum
+ else:
+ bn = busnum
+ dn = devnum
+ ctrl = DF10CHController(handle, bn, dn, dev.deviceVersion, serial)
+ DeviceList.append(ctrl)
+ except usb.USBError:
+ pass
+ devnum = devnum + 1
+ busnum = busnum + 1
+
+
+def ReleaseDevices():
+ global DeviceList
+ for dev in DeviceList:
+ try:
+ dev.release()
+ except usb.USBError:
+ pass
+ DeviceList = list()
+
+
+ConfigMap = dict()
+
+def LoadConfigs():
+ global ConfigMap, DeviceList
+ ConfigMap = dict()
+ FindDevices()
+ for ctrl in DeviceList:
+ if not ctrl.bootloader_mode() and not ctrl.get_pwm_bootloader_mode():
+ config = ControllerConfig(ctrl)
+ ConfigMap[ctrl.id] = config
+
+
+if __name__ == "__main__":
+ def calc_gamma_tab(gamma, max_pwm):
+ result = list();
+ for i in range (256):
+ v = pow (i / 255.0, gamma)
+ iv = int(round(v * max_pwm))
+ result.append(iv)
+ return result
+
+ FindDevices()
+ if len(DeviceList):
+ dev = DeviceList[0]
+
+ #dev.set_reply_timeout(150, 10)
+
+ if 0:
+# data = range(128, 0, -1)
+# print "write"
+# dev.write_ee_data(0, data)
+ print "read"
+ for i in range(50):
+ eedata = dev.read_ee_data(0, 254)
+ print eedata
+
+ #print "set reply timeout"
+ #dev.set_reply_timeout(950,5)
+
+ if 1:
+ import firmware
+ fw = firmware.FlashMem("/home/andy/python_ws/df10ch/pwm_ctrl/10ch_pwm_ctrl.dff", 128, True)
+ if dev.bootloader_mode():
+ dev.start_appl()
+ time.sleep(5)
+ if not dev.get_pwm_bootloader_mode():
+ dev.start_pwm_ctrl_bootloader()
+ print dev.bootloader_mode(), dev.get_pwm_bootloader_mode()
+ try:
+ for i in range(50):
+ print i
+ for fp in fw.pageList:
+ #print fp.baseAddr
+ data = dev.read_pwm_flash(fp.baseAddr, fp.pageSize)
+ fp.verify(data)
+ except:
+ pass
+ print "get request error status"
+ stat = dev.get_bootloader_request_error_status()
+ print GetCommErrMsg(stat)
+
+ if 0:
+ print 'get pwm version'
+ v = dev.get_pwm_version()
+ print "pwm version: ", v
+
+ if 0:
+ print 'set brighness'
+ #dev.set_pwm_freq(100)
+ f = dev.get_pwm_freq()
+ print "freq: ", f
+ m = dev.get_max_pwm_value()
+ print "max pwm: ", m
+ gtab = calc_gamma_tab(2.2, m)
+ #while 1:
+ t = time.clock()
+ n = 0
+ for i in range(9):
+ for v in range(NBRIGHTS):
+ data = [ gtab[v] ]
+ dev.set_brightness_synced(i, data)
+ n = n + 1
+ for v in range(NBRIGHTS-1,-1,-1):
+ data = [ gtab[v] ]
+ dev.set_brightness_synced(i, data)
+ n = n + 1
+ t1 = time.clock()
+ print "mean time ", (t1 - t) / n
+ print "get request error status"
+ stat = dev.get_request_error_status()
+ print GetCommErrMsg(stat)
+ print "get reply error status"
+ stat = dev.get_reply_error_status()
+ print GetCommErrMsg(stat)
+
+ if 0:
+ print 'set brighness'
+ dev.set_pwm_freq(100)
+ f = dev.get_pwm_freq()
+ print "freq: ", f
+ m = dev.get_max_pwm_value()
+ print "max pwm: ", m
+ gtab = calc_gamma_tab(2.2, m)
+ rows = list()
+ for i in range(256):
+ data = list()
+ for c in range(30):
+ v = i + c
+ if v >= NBRIGHTS:
+ v = v - NBRIGHTS
+ data.append(gtab[v])
+ rows.append(data)
+ data = list()
+ for c in range(30):
+ v = NBRIGHTS - i - c - 1
+ if v < 0:
+ v = v + NBRIGHTS
+ data.append(gtab[v])
+ rows.append(data)
+ while 1:
+ t = time.clock()
+ n = 0
+ for data in rows:
+ dev.set_brightness(0, data)
+ n = n + 1
+ t1 = time.clock()
+ print "mean time ", (t1 - t) / n
+ stat = dev.get_request_error_status()
+ if stat:
+ print "get request error status"
+ print GetCommErrMsg(stat)
+ stat = dev.get_reply_error_status()
+ if stat:
+ print "get reply error status"
+ print GetCommErrMsg(stat)
+
+ if 0:
+ print 'get channel map'
+ data = dev.get_channel_map(0, NCHANNELS)
+ print data
+
+ if 0:
+ print "common brightness test"
+ data = [ 255, 255, 255, 255, 255, 255, 255, 255, 255 ]
+ dev.set_brightness(0, data)
+ for v in range(NBRIGHTS-1,-1,-1):
+ print v
+ dev.set_common_brightness(v)
+ time.sleep(0.01)
+ time.sleep(1)
+ for v in range(NBRIGHTS):
+ dev.set_common_brightness(v)
+ time.sleep(0.01)
+
+ if 0:
+ print "reset setup"
+ dev.reset_setup()
+
+ if 0:
+ print "store setup"
+ dev.store_setup()
+
+ if 0:
+ print "get request error status"
+ stat = dev.get_request_error_status()
+ print GetCommErrMsg(stat)
+
+ if 1:
+ print "get reply error status"
+ stat = dev.get_reply_error_status()
+ print GetCommErrMsg(stat)
+ else:
+ print "No controller found!"
+
+
+
diff --git a/df10ch_setup_pkg/firmware.py b/df10ch_setup_pkg/firmware.py
new file mode 100644
index 0000000..24dc577
--- /dev/null
+++ b/df10ch_setup_pkg/firmware.py
@@ -0,0 +1,135 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+import array
+import fileinput
+import string
+
+class FirmwareFlashError(Exception):
+ def __init__(self, msg = None):
+ self.message = msg
+
+ def __str__(self):
+ return self.message
+
+
+class FlashPage:
+
+ def __init__(self, addr, pageSize):
+ self.pageSize = pageSize
+ self.baseAddr = addr - addr % pageSize
+ self.data = array.array('B', [ 0xFF ] * pageSize)
+
+ def insert(self, addr, value):
+ self.data[addr % self.pageSize] = value
+
+ def verify(self, data):
+ for i in range(self.pageSize):
+ if data[i] != self.data[i]:
+ raise FirmwareFlashError("verify of flash data against firmware fails at {0:04X}: {1:02X} <> {2:02X}".format(self.baseAddr + i, data[i], self.data[i]))
+
+ def __str__(self):
+ s = "{0:04X}: ".format(self.baseAddr)
+ for v in self.data:
+ s = s + "{0:02X} ".format(v)
+ return s
+
+
+class FlashMem:
+
+ def __init__(self, fileName, pageSize, targetInfoMustExist = False):
+ self.pageSize = pageSize
+ self.pageList = list()
+ self.lastLookupPage = None
+ self.target = None
+ self.version = None
+ self.loadFromHexFile(fileName)
+ if targetInfoMustExist and (not self.target or not self.version):
+ raise FirmwareFlashError("no target and/or version information found!")
+
+ def getPageForAddr(self, addr):
+ baseAddr = addr - addr % self.pageSize
+ if self.lastLookupPage and self.lastLookupPage.baseAddr == baseAddr:
+ return self.lastLookupPage;
+ for p in self.pageList:
+ if p.baseAddr == baseAddr:
+ self.lastLookupPage = p
+ return p
+ return None
+
+ def insert(self, addr, value):
+ p = self.getPageForAddr(addr)
+ if not p:
+ p = FlashPage(addr, self.pageSize)
+ self.pageList.append(p)
+ p.insert(addr, value)
+
+ def loadFromHexFile(self, fileName):
+ file = None
+ try:
+ file = fileinput.FileInput(fileName)
+ for line in file:
+ line = string.rstrip(line)
+ lineLen = len(line)
+ if not lineLen:
+ continue
+ lineType = line[0:1]
+ if lineType == "#":
+ continue
+ if lineType == "@":
+ try:
+ self.target, self.version = string.split(line[1:])
+ except:
+ raise FirmwareFlashError()
+ continue
+ if lineLen < 9 or lineType != ":":
+ raise FirmwareFlashError()
+ try:
+ n = int(line[1:3], 16)
+ addr = int(line[3:7], 16)
+ type = int(line[7:9], 16)
+ except:
+ raise FirmwareFlashError()
+ if type != 0:
+ break
+ if n > 0:
+ if lineLen < (9 + 2 * n):
+ raise FirmwareFlashError()
+ for i in range(n):
+ try:
+ data = int(line[i * 2 + 9: i * 2 + 11], 16)
+ except:
+ raise FirmwareFlashError()
+ self.insert(addr + i, data)
+ except IOError as err:
+ raise FirmwareFlashError("could not read firmware file '{0}': {1}".format(fileName, err.__str__()))
+ except FirmwareFlashError:
+ raise FirmwareFlashError("could not read firmware file '{0}': syntax error at line {1}".format(fileName, file.lineno()))
+ finally:
+ if file:
+ file.close()
+
+if __name__ == "__main__":
+ m = FlashMem("10ch_usb_ctrl.hex", 16)
+ print "target:", m.target, "version:", m.version
+ for p in m.pageList:
+ print p \ No newline at end of file
diff --git a/df10ch_setup_pkg/layout_dlg.py b/df10ch_setup_pkg/layout_dlg.py
new file mode 100644
index 0000000..500c029
--- /dev/null
+++ b/df10ch_setup_pkg/layout_dlg.py
@@ -0,0 +1,111 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+from Tkinter import *
+import tkFont
+
+import device_drv
+
+
+class LayoutDialog:
+ def __init__(self, areasDlg, master=None, **args):
+ self.areasDlg = areasDlg
+ self.numAreas = [ 0 ] * device_drv.NumBaseAreas()
+ self.varNumAreas = list()
+ for i in range(device_drv.NumBaseAreas()):
+ self.varNumAreas.append(StringVar())
+
+ root = Frame(master, **args)
+ self.root = root
+
+ Label(root, text="Configure RGB-Areas", font=tkFont.Font(weight="bold")).grid(row=0, column=0, columnspan=5, padx=5, pady=5)
+ Label(root, text="Top").grid(row=1, column=2)
+ Label(root, text="TopLeft").grid(row=1, column=0, sticky=E)
+ Label(root, text="Left").grid(row=3, column=0, sticky=E)
+ Label(root, text="BottomLeft").grid(row=5, column=0, sticky=E)
+ Label(root, text="TopRight").grid(row=1, column=4, sticky=W)
+ Label(root, text="Right").grid(row=3, column=4, sticky=W)
+ Label(root, text="BottomRight").grid(row=5, column=4, sticky=W)
+ Label(root, text="Bottom").grid(row=5, column=2)
+
+ i = device_drv.AreaIndex("TopLeft")
+ self.sbTopLeft = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], width=2)
+ self.sbTopLeft.grid(row=2, column=1, padx=5, pady=5)
+
+ i = device_drv.AreaIndex("TopRight")
+ self.sbTopRight = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], width=2)
+ self.sbTopRight.grid(row=2, column=3, padx=5, pady=5)
+
+ i = device_drv.AreaIndex("BottomLeft")
+ self.sbBottomLeft = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], width=2)
+ self.sbBottomLeft.grid(row=4, column=1, padx=5, pady=5)
+
+ i = device_drv.AreaIndex("BottomRight")
+ self.sbBottomRight = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], width=2)
+ self.sbBottomRight.grid(row=4, column=3, padx=5, pady=5)
+
+ i = device_drv.AreaIndex("Center")
+ self.sbCenter = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], width=2)
+ self.sbCenter.grid(row=3, column=2, padx=20, pady=20)
+
+ i = device_drv.AreaIndex("Top")
+ self.sbTop = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], increment=1, width=3)
+ self.sbTop.grid(row=2, column=2, padx=5, pady=5)
+
+ i = device_drv.AreaIndex("Bottom")
+ self.sbBottom = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], increment=1, width=3)
+ self.sbBottom.grid(row=4, column=2, padx=5, pady=5)
+
+ i = device_drv.AreaIndex("Left")
+ self.sbLeft = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], increment=1, width=3)
+ self.sbLeft.grid(row=3, column=1, padx=5, pady=5)
+
+ i = device_drv.AreaIndex("Right")
+ self.sbRight = Spinbox(root, textvariable=self.varNumAreas[i], from_=0, to=device_drv.MAX_AREAS[i], increment=1, width=3)
+ self.sbRight.grid(row=3, column=3, padx=5, pady=5)
+
+ self.btApply = Button(root, text="Apply", command=self.cbApply)
+ self.btApply.grid(row=6, column=4, padx=20, pady=20, ipadx=5)
+
+ def cbApply(self):
+ for i in range(device_drv.NumBaseAreas()):
+ self.numAreas[i] = int(self.varNumAreas[i].get())
+ self.areasDlg.configAreas(self.numAreas)
+
+ def setLayoutFromConfig(self):
+ for i in range(device_drv.NumBaseAreas()):
+ self.numAreas[i] = 0
+ for ctrlId in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[ctrlId]
+ for i in range(device_drv.NumBaseAreas()):
+ if config.numAreas[i] > self.numAreas[i]:
+ self.numAreas[i] = config.numAreas[i]
+ for i in range(device_drv.NumBaseAreas()):
+ self.varNumAreas[i].set(self.numAreas[i])
+ self.areasDlg.configAreas(self.numAreas)
+
+ def setConfigFromLayout(self):
+ for ctrlId in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[ctrlId]
+ for i in range(device_drv.NumBaseAreas()):
+ config.numAreas[i] = self.numAreas[i]
+
diff --git a/df10ch_setup_pkg/map_dlg.py b/df10ch_setup_pkg/map_dlg.py
new file mode 100644
index 0000000..b8cd575
--- /dev/null
+++ b/df10ch_setup_pkg/map_dlg.py
@@ -0,0 +1,256 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+from Tkinter import *
+import tkFont
+import tkMessageBox
+import device_drv
+import string
+
+class ChannelMapDialog:
+ def __init__(self, areasDlg, master=None, **args):
+ self.areasDlg = areasDlg
+ areasDlg.selectCallbacks.append(self)
+
+ self.actualIdx = None
+ self.actualCtrlId = None
+ self.actualPortName = None
+ self.actualArea = None
+ self.actualColor = None
+ self.channelList = None
+
+ root = Frame(master, **args)
+ self.root = root
+ root.bind("<Map>", self.cbSheetSelected)
+
+ Label(root, text="Channel Mapping", font=tkFont.Font(weight="bold")).grid(row=0, column=0, columnspan=4, padx=5, pady=5)
+
+ self.yScroll = Scrollbar (root, orient=VERTICAL)
+ self.yScroll.grid(row=1, column=1, rowspan=4, sticky=N+S)
+ self.lbChannels = Listbox(root, selectmode=SINGLE, activestyle=NONE, width=35, height=30, yscrollcommand=self.yScroll.set)
+ self.lbChannels.grid(row=1, column=0, rowspan=4, padx=5, pady=5, sticky=N+S+W+E)
+ self.lbChannels.bind("<ButtonRelease-1>", self.cbSelectChannel)
+ self.yScroll["command"] = self.lbChannels.yview
+
+ frSingleColor = Frame(root, borderwidth=5, relief=RIDGE, padx=0, pady=0)
+ frSingleColor.grid(row=2, column = 2, columnspan = 2, padx=5, pady=5, sticky=W+E)
+
+ Label(frSingleColor, text="Set color for channel:").grid(row=0, column=0, columnspan=3, padx=5, pady=5, sticky="W")
+
+ self.btRed = Button(frSingleColor, text="Red", bg="red", command=lambda: self.cbSetColor("red"))
+ self.btRed.grid(row=1, column=0, padx=5, pady=5, ipadx=5, sticky=W+E)
+
+ self.btGreen = Button(frSingleColor, text="Green", bg="green", command=lambda: self.cbSetColor("green"))
+ self.btGreen.grid(row=1, column=1, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+ self.btBlue = Button(frSingleColor, text="Blue", bg="blue", command=lambda: self.cbSetColor("blue"))
+ self.btBlue.grid(row=1, column=2, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+ frGroupColor = Frame(root, borderwidth=5, relief=RIDGE, padx=0, pady=0)
+ frGroupColor.grid(row = 3, column = 2, columnspan = 2, padx=5, pady=5, sticky=W+E)
+
+ Label(frGroupColor, text="Set color for channel group:").grid(row=0, column=0, columnspan=3, padx=5, pady=5, sticky="W")
+
+ self.btRGB = Button(frGroupColor, text="RGB", command=lambda: self.cbSetGroupColor("red", "green", "blue"))
+ self.btRGB.grid(row=1, column=0, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+ self.btRBG = Button(frGroupColor, text="RBG", command=lambda: self.cbSetGroupColor("red", "blue", "green"))
+ self.btRBG.grid(row=1, column=1, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+ self.btBRG = Button(frGroupColor, text="GRB", command=lambda: self.cbSetGroupColor("green", "red", "blue"))
+ self.btBRG.grid(row=1, column=2, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+ self.btGRB = Button(frGroupColor, text="BRG", command=lambda: self.cbSetGroupColor("blue", "red", "green"))
+ self.btGRB.grid(row=2, column=0, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+ self.btBGR = Button(frGroupColor, text="GBR", command=lambda: self.cbSetGroupColor("green", "blue", "red"))
+ self.btBGR.grid(row=2, column=1, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+ self.btGBR = Button(frGroupColor, text="BGR", command=lambda: self.cbSetGroupColor("blue", "green", "red"))
+ self.btGBR.grid(row=2, column=2, padx=5, pady=5, ipadx = 5, sticky=W)
+
+ #frNavi = Frame(root, padx=0, pady=0)
+ #frNavi.grid(row = 1, column = 2, columnspan = 2, padx=5, pady=5, sticky=N+S+W+E)
+
+ self.btNext = Button(root, text="Next Ch", command=self.cbNext)
+ self.btNext.grid(row=1, column=2, padx=5, pady=5, ipadx=5, sticky=W+E)
+
+ self.btPrev = Button(root, text="Prev Ch", command=self.cbPrev)
+ self.btPrev.grid(row=1, column=3, padx=5, pady=5, ipadx=5, sticky=W+E)
+
+ self.btDelete = Button(root, text="Delete mapping", command=self.cbDelete)
+ self.btDelete.grid(row=4, column=2, columnspan=2, padx=5, pady=5, ipadx = 5, sticky=W+E)
+
+
+ def cbSelectChannel(self, event):
+ s = self.lbChannels.curselection()
+ if len(s) == 1:
+ self.selectChannel(int(s[0]))
+
+ def cbAreaSelected(self):
+ if self.root.winfo_ismapped() and self.actualIdx != None:
+ self.selectArea(self.areasDlg.selectedArea, self.actualColor)
+ self.storeActual()
+
+ def cbSetGroupColor(self, *colors):
+ actIdx = self.actualIdx
+ if actIdx != None:
+ port, p = string.split(self.actualPortName, ".")
+ for pinNum in range(3):
+ portName = "{0}.{1}".format(port, pinNum + 1)
+ for i, mapRec in enumerate(self.channelList):
+ if mapRec['ctrlId'] == self.actualCtrlId and mapRec['portName'] == portName:
+ self.actualPortName = portName
+ self.actualColor = colors[pinNum]
+ self.actualIdx = i
+ self.storeActual()
+ break
+ self.selectChannel(actIdx)
+
+ def cbSetColor(self, color):
+ if self.actualIdx != None:
+ self.selectArea(self.actualArea, color)
+ self.storeActual()
+
+ def cbDelete(self):
+ if self.actualIdx != None:
+ self.storeActual(True)
+
+ def cbNext(self):
+ if self.actualIdx != None:
+ i = self.actualIdx + 1
+ if i == len(self.channelList):
+ i = 0
+ self.selectChannel(i)
+
+ def cbPrev(self):
+ if self.actualIdx != None:
+ i = self.actualIdx - 1
+ if i < 0:
+ i = len(self.channelList) - 1
+ self.selectChannel(i)
+
+ def cbSheetSelected(self, event):
+ self.loadValues()
+
+ def storeActual(self, delete=False):
+ config = device_drv.ConfigMap[self.actualCtrlId]
+ if delete:
+ config.channelMap[self.actualPortName] = None
+ self.channelList[self.actualIdx] = dict(ctrlId=self.actualCtrlId, portName=self.actualPortName, area=None, color=None)
+ else:
+ self.channelList[self.actualIdx] = dict(ctrlId=self.actualCtrlId, portName=self.actualPortName, area=self.actualArea, color=self.actualColor)
+
+ if not delete and self.actualArea and self.actualColor:
+ configMapRec = config.channelMap[self.actualPortName]
+ if configMapRec:
+ configMapRec['area'] = self.actualArea
+ configMapRec['color'] = device_drv.ColorIndex(self.actualColor)
+ else:
+ configMapRec = dict(area=self.actualArea, color=device_drv.ColorIndex(self.actualColor), gamma=device_drv.DEFAULT_GAMMA_VAL, whiteCal=config.pwmRes)
+ config.channelMap[self.actualPortName] = configMapRec
+ text = "{0}: {1} -> {2}: {3}".format(self.actualCtrlId, self.actualPortName, self.actualArea, self.actualColor)
+ else:
+ text = "{0}: {1}".format(self.actualCtrlId, self.actualPortName)
+
+ self.lbChannels.delete(self.actualIdx, self.actualIdx)
+ self.lbChannels.insert(self.actualIdx, text)
+ self.lbChannels.selection_set(self.actualIdx)
+
+ def loadValues(self):
+ self.actualIdx = None
+ self.channelList = list()
+ self.lbChannels.delete(0, END)
+ for ctrlId in sorted(device_drv.ConfigMap.keys()):
+ config = device_drv.ConfigMap[ctrlId]
+ for portName in sorted(config.channelMap.keys()):
+ configMapRec = config.channelMap[portName]
+ if configMapRec:
+ area = configMapRec['area']
+ color = device_drv.ColorName(configMapRec['color'])
+ text = "{0}: {1} -> {2}: {3}".format(ctrlId, portName, area, color)
+ else:
+ area = None
+ color = None
+ text = "{0}: {1}".format(ctrlId, portName)
+ self.channelList.append(dict(ctrlId=ctrlId, portName=portName, area=area, color=color))
+ self.lbChannels.insert(END, text)
+
+ pwmChannelMap = list()
+ while len(pwmChannelMap) < device_drv.NCHANNELS:
+ pwmChannelMap.append(dict(channel=0, port=0, pins=0))
+
+ try:
+ config.ctrl.set_channel_map(0, pwmChannelMap)
+ config.ctrl.set_brightness(0, [ config.pwmRes ] + [ 0 ] * (device_drv.NCHANNELS - 1))
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ return
+
+ self.areasDlg.initAreas("black")
+ self.actualCtrlId = None
+ self.actualPortName = None
+ if len(self.channelList):
+ self.selectChannel(0)
+
+ def selectChannel(self, i):
+ self.actualIdx = i
+
+ self.lbChannels.selection_clear(0, END)
+ self.lbChannels.selection_set(i)
+ self.lbChannels.see(i)
+
+ mapRec = self.channelList[i]
+ self.selectLight(mapRec['ctrlId'], mapRec['portName'])
+ self.selectArea(mapRec['area'], mapRec['color'])
+
+ def selectLight(self, ctrlId, portName):
+ if ctrlId != self.actualCtrlId or portName != self.actualPortName:
+ if self.actualCtrlId and ctrlId != self.actualCtrlId:
+ config = device_drv.ConfigMap[self.actualCtrlId]
+ try:
+ config.ctrl.set_channel_map(0, [ dict(channel=0, port=0, pins=0) ])
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ return
+
+ port, pin = device_drv.PORT_NAME_MAP[portName]
+ config = device_drv.ConfigMap[ctrlId]
+ try:
+ config.ctrl.set_channel_map(0, [ dict(channel=0, port=port, pins=pin) ])
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ return
+
+ self.actualCtrlId = ctrlId
+ self.actualPortName = portName
+
+ def selectArea(self, area, color):
+ if self.actualArea:
+ self.areasDlg.setAreaColor(self.actualArea, "black")
+ self.actualColor = color
+ if area:
+ self.actualArea = area
+ if not color:
+ color = "black"
+ self.areasDlg.setAreaColor(area, color)
+ self.areasDlg.selectArea(area)
diff --git a/df10ch_setup_pkg/setup_dlg.py b/df10ch_setup_pkg/setup_dlg.py
new file mode 100644
index 0000000..23fc853
--- /dev/null
+++ b/df10ch_setup_pkg/setup_dlg.py
@@ -0,0 +1,58 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+from Tkinter import *
+
+class SetupDialog:
+
+ def __init__(self, master, side=LEFT):
+
+ self.activeSheet = None
+ self.count = 0
+ self.choice = IntVar(0)
+
+ if side in (TOP, BOTTOM):
+ self.side = LEFT
+ else:
+ self.side = TOP
+
+ self.tabsMaster = Frame(master, borderwidth=2, relief=RIDGE)
+ self.tabsMaster.pack(side=side, fill=BOTH)
+ self.sheetMaster = Frame(master, borderwidth=2, relief=RIDGE)
+ self.sheetMaster.pack(fill=BOTH)
+
+
+ def addSheet(self, sheet, title):
+ b = Radiobutton(self.tabsMaster, text=title, padx=5, pady=10, indicatoron=0, \
+ variable=self.choice, value=self.count, \
+ command=lambda: self.displaySheet(sheet))
+ b.pack(fill=BOTH, side=self.side)
+ if not self.activeSheet:
+ sheet.pack(fill=BOTH, expand=1)
+ self.activeSheet = sheet
+ self.count += 1
+
+
+ def displaySheet(self, sheet):
+ self.activeSheet.forget()
+ sheet.pack(fill=BOTH, expand=1)
+ self.activeSheet = sheet
diff --git a/df10ch_setup_pkg/white_cal_dlg.py b/df10ch_setup_pkg/white_cal_dlg.py
new file mode 100644
index 0000000..3843e78
--- /dev/null
+++ b/df10ch_setup_pkg/white_cal_dlg.py
@@ -0,0 +1,172 @@
+#
+# Copyright (C) 2010 Andreas Auras
+#
+# This file is part of the DF10CH Atmolight controller project.
+#
+# DF10CH Atmolight controller is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# DF10CH Atmolight controller is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+#
+# This file is part of the DF10CH setup program
+#
+
+from Tkinter import *
+import tkFont
+import tkMessageBox
+import device_drv
+
+
+class WhiteCalDialog:
+ def __init__(self, areasDlg, master=None, **args):
+ self.areasMap = None
+ self.selectedArea = None
+
+ self.areasDlg = areasDlg
+ areasDlg.selectCallbacks.append(self)
+
+ root = Frame(master, **args)
+ self.root = root
+ root.bind("<Map>", self.cbSheetSelected)
+
+ Label(root, text="White Calibration", font=tkFont.Font(weight="bold")).grid(row=0, column=0, columnspan=5, padx=5, pady=5)
+ Label(root, text="Max. value:").grid(row=1, column=0, sticky=E)
+ Label(root, text="Gamma value:").grid(row=2, column=0, sticky=E)
+
+
+ self.varWhiteCal = DoubleVar(), DoubleVar(), DoubleVar()
+ self.scRed = Scale(root, label="Red", bg="red", length=200, from_=1.0, to=0.0, resolution=0.01, orient=VERTICAL, variable=self.varWhiteCal[device_drv.ColorIndex("red")], command=self.cbSetWhiteCal)
+ self.scRed.grid(row=1, column=1, rowspan=1, padx=5, pady=5)
+ self.scGreen = Scale(root, label="Green", bg="green", length=200, from_=1.0, to=0.0, resolution=0.01, orient=VERTICAL, variable=self.varWhiteCal[device_drv.ColorIndex("green")], command=self.cbSetWhiteCal)
+ self.scGreen.grid(row=1, column=2, rowspan=1, padx=5, pady=5)
+ self.scBlue = Scale(root, label="Blue", bg="blue", length=200, from_=1.0, to=0.0, resolution=0.01, orient=VERTICAL, variable=self.varWhiteCal[device_drv.ColorIndex("blue")], command=self.cbSetWhiteCal)
+ self.scBlue.grid(row=1, column=3, rowspan=1, padx=5, pady=5)
+
+ self.varGamma = StringVar(), StringVar(), StringVar()
+ self.sbRed = Spinbox(root, textvariable=self.varGamma[device_drv.ColorIndex("red")], from_=device_drv.MIN_GAMMA_VAL/10.0, to=device_drv.MAX_GAMMA_VAL/10.0, format='%2.1f', increment=0.1, width=2, command=self.cbSetGamma)
+ self.sbRed.grid(row=2, column=1, padx=5, pady=5, sticky=W+E)
+ self.sbGreen = Spinbox(root, textvariable=self.varGamma[device_drv.ColorIndex("green")], from_=device_drv.MIN_GAMMA_VAL/10.0, to=device_drv.MAX_GAMMA_VAL/10.0, format='%2.1f', increment=0.1, width=2, command=self.cbSetGamma)
+ self.sbGreen.grid(row=2, column=2, padx=5, pady=5, sticky=W+E)
+ self.sbBlue = Spinbox(root, textvariable=self.varGamma[device_drv.ColorIndex("blue")], from_=device_drv.MIN_GAMMA_VAL/10.0, to=device_drv.MAX_GAMMA_VAL/10.0, format='%2.1f', increment=0.1, width=2, command=self.cbSetGamma)
+ self.sbBlue.grid(row=2, column=3, padx=5, pady=5, sticky=W+E)
+
+ self.varBright = DoubleVar()
+ self.scBright = Scale(root, label="Brightness", length=200, from_=1.00, to=0.0, resolution=0.01, orient=VERTICAL, variable=self.varBright, command=self.cbSetBright)
+ self.scBright.grid(row=1, column=4, rowspan=1, padx=20, pady=5)
+ self.varBright.set(1.0)
+
+ self.varSelectAll = IntVar()
+ self.btSelectAll = Checkbutton(root, text="Select All", command=self.cbSelectAll, variable=self.varSelectAll)
+ self.btSelectAll.grid(row=2, column=4, padx=20, pady=20, ipadx=5, sticky=W+E)
+
+
+ def cbSelectAll(self):
+ self.setBright()
+
+ def cbSheetSelected(self, event):
+ self.loadValues()
+
+ def cbSetWhiteCal(self, val):
+ self.update()
+
+ def cbSetGamma(self):
+ self.update()
+
+ def cbSetBright(self, val):
+ self.setBright()
+
+ def cbAreaSelected(self):
+ if self.root.winfo_ismapped():
+ self.selectArea(self.areasDlg.selectedArea)
+
+ def loadValues(self):
+ self.areasMap = dict()
+ area = None
+ for ctrlId in device_drv.ConfigMap.keys():
+ config = device_drv.ConfigMap[ctrlId]
+ pwmChannelMap = list()
+ brightList = list()
+ reqChannel = 0
+ for portName in config.channelMap.keys():
+ configMapRec = config.channelMap[portName]
+ if configMapRec:
+ port, pin = device_drv.PORT_NAME_MAP[portName]
+ pwmChannelMap.append(dict(channel=reqChannel, port=port, pins=pin))
+ area = configMapRec['area']
+ gamma = configMapRec['gamma'] / 10.0
+ whiteCal = configMapRec['whiteCal']
+ bright = int(round(pow(self.varBright.get(), gamma) * whiteCal))
+ brightList.append(bright)
+ cRec = dict(ctrlId=ctrlId, portName=portName, configMapRec=configMapRec, reqChannel=reqChannel)
+ if not area in self.areasMap: self.areasMap[area] = list()
+ self.areasMap[area].append(cRec)
+ reqChannel = reqChannel + 1
+
+ while reqChannel < device_drv.NCHANNELS:
+ brightList.append(0)
+ pwmChannelMap.append(dict(channel=0, port=0, pins=0))
+ reqChannel = reqChannel + 1
+
+ try:
+ config.ctrl.set_channel_map(0, pwmChannelMap)
+ config.ctrl.set_brightness(0, brightList)
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ return
+
+ if area:
+ self.selectArea(area)
+ self.setBright()
+
+ def setBright(self):
+ self.areasDlg.initAreas("#{0:02X}{0:02X}{0:02X}".format(int(round(self.varBright.get() * 255.0))))
+ if not self.varSelectAll.get() and self.selectedArea:
+ self.areasDlg.selectArea(self.selectedArea)
+ self.update()
+
+ def selectArea(self, area):
+ if area in self.areasMap:
+ self.varSelectAll.set(0)
+ self.selectedArea = area
+ self.areasDlg.selectArea(area)
+ for cRec in self.areasMap[area]:
+ ctrlId = cRec['ctrlId']
+ config = device_drv.ConfigMap[ctrlId]
+ configMapRec = cRec['configMapRec']
+ color = configMapRec['color']
+ whiteCal = float(configMapRec['whiteCal']) / float(config.pwmRes)
+ gamma = float(configMapRec['gamma']) / 10.0
+ self.varGamma[color].set(gamma)
+ self.varWhiteCal[color].set(whiteCal)
+
+ def update(self):
+ for area in self.areasMap.keys():
+ for cRec in self.areasMap[area]:
+ ctrlId = cRec['ctrlId']
+ reqChannel = cRec['reqChannel']
+ configMapRec = cRec['configMapRec']
+ color = configMapRec['color']
+ config = device_drv.ConfigMap[ctrlId]
+ if self.varSelectAll.get() or self.selectedArea == area:
+ gamma = float(self.varGamma[color].get())
+ whiteCal = int(self.varWhiteCal[color].get() * config.pwmRes)
+ configMapRec['gamma'] = int(gamma * 10.0)
+ configMapRec['whiteCal'] = whiteCal
+ else:
+ gamma = float(configMapRec['gamma']) / 10.0
+ whiteCal = configMapRec['whiteCal']
+ bright = int(round(pow(self.varBright.get(), gamma) * whiteCal))
+ try:
+ config.ctrl.set_brightness(reqChannel, [ bright ])
+ except device_drv.AtmoControllerError as err:
+ tkMessageBox.showerror(self.root.winfo_toplevel().title(), err.__str__())
+ return