spokecharinterleaved.py

来自「旋转16个LED灯控制程序」· Python 代码 · 共 1,043 行 · 第 1/3 页

PY
1,043
字号
#!/usr/bin/env python

# The software for SpokePOV is available for use in accordance with the 
# following open source license (MIT License). For more information about
# OS licensing, please visit -> http://www.opensource.org/
#
# For more information about SpokePOV, please visit
# -> http://www.ladyada.net/make/spokepov
#
#                                     *****
# Copyright (c) 2005 Limor Fried
#
# Permission is hereby granted, free of charge, to any person obtaining a 
# copy of this software and associated documentation files (the "Software"), 
# to deal in the Software without restriction, including without limitation 
# the rights to use, copy, modify, merge, publish, distribute, sublicense, 
# and/or sell copies of the Software, and to permit persons to whom the 
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in 
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#                                     *****

# SpokeChar.py was cribbed from SpokePOV.py by Robert Woodhead, trebor@animeigo.com,
# changes (c) 2006 Robert Woodhead, released under the above license.

import sys, time
import parallel
import array
import wx
import math
import ConfigParser
import pickle

import  wx.lib.editor    as  editor

# Note: this is my first Python/wx program. It probably has mistakes, bugs,
# bad code. Oh well.  -- ladyada

# RJW 06/30/06 - pretty much my first Python program too.  This nesting
# determined by the indentation stuff is a total brainfart, IMHO.
#
# I have deleted stuff that isn't really needed but some stuff is still
# leftover from SpokePOV.py

#default rotation
autorotation = 0

#default hub diameter is 2" (*4 LEDs per inch)
hubsize = 2*4

#default LEDs per row is 30, BMX wheels have 22
num_leds = 30

############## spoke interface commands, must be the same in firmware!

COMP_CMD_SETFLED = 0x81
COMP_CMD_SETBLED = 0x82
COMP_CMD_CLRFLED = 0x83
COMP_CMD_CLRBLED = 0x84
COMP_CMD_RDEEPROM = 0x85
COMP_CMD_WREEPROM = 0x86
COMP_CMD_RDEEPROM16 = 0x87
COMP_CMD_WREEPROM16 = 0x88
COMP_SUCCESS = 0x80

############## spokepov parallel port pins

SPI_CLK = 3;    # DATA3
SPI_DO = 0;     # DATA0

############## variables stored in the microcontroller

EEPROM_ROTOFFSET = 0x8000
EEPROM_MIRROR = 0x8001

####################################################
# this class talks to the actual spokes
####################################################

class SpokePOVComm:
    def __init__(self):
        self.p = parallel.Parallel()  # open LPT1
        self.out(0xFF)

    # if there's a spokepov on the other side, this pin should be low
    
    def connected(self):
        r = ~ self.p.getInAcknowledge()
        return r

    # since theres only a byte-wide byte output function, these functions
    # allow setting and clearing individual pins

    def out(self, b):
        self.data = b
        self.p.setData(self.data)

    def setbit(self, b):
        self.data |= 1 << b
        self.p.setData(self.data)

    def clrbit(self, b):
        self.data &= ~(1 << b)
        self.p.setData(self.data)

    # bit-bang the SPI protocol over to the microcontroller

    def spi_xfer(self, c):
        #print "sending %02x\n" % c
        x = 7
        ret = 0
        
        while x >= 0:
            
            if (self.connected() == 0):
                raise IOError, "not connected"

            # send data out
            if c & (1 << x):
                self.setbit(SPI_DO)
            else:
                self.clrbit(SPI_DO)
            self.setbit(SPI_CLK)

            #print "^"
            #ya = raw_input()

            time.sleep(0.001)

            # get data in
            ret <<= 1
            ret |= self.p.getInBusy()
            
            self.clrbit(SPI_CLK)
            time.sleep(0.001)

            #print "v"
            #ya = raw_input()

            
            x -= 1

        #print "got %02x" % ret
        return ret

    # read one byte from the external EEPROM

    def read_eeprom(self, addr):
        self.spi_xfer(COMP_CMD_RDEEPROM)
        #time.sleep(0.01)
        self.spi_xfer((addr >> 8) & 0xFF)
        #time.sleep(0.01)
        self.spi_xfer(addr & 0xFF)
        #time.sleep(0.01)
        val = self.spi_xfer(0)
        #time.sleep(0.01)
        ret = self.spi_xfer(0);
        if (ret != 0x80):
            print "failed! 0x%02x" % ret
            raise IOError, "Didn't succeed"        
        return val

    # read 16 bytes from the external EEPROM (faster!)

    def read_eeprom16(self, addr):
        self.spi_xfer(COMP_CMD_RDEEPROM16)
        self.spi_xfer((addr >> 8) & 0xFF)
        self.spi_xfer(addr & 0xFF)
        x = 16
        val = []
        while (x != 0):
            val.append(self.spi_xfer(0))
            x -= 1
            
        ret = self.spi_xfer(0);
        if (ret != 0x80):
            raise IOError, "Didn't succeed"        
        return val

    # write a byte to the external EEPROM
    
    def write_eeprom(self, addr, val):
        self.spi_xfer(COMP_CMD_WREEPROM)
        self.spi_xfer((addr >> 8) & 0xFF)
        self.spi_xfer(addr & 0xFF)
        self.spi_xfer(val)
        ret = self.spi_xfer(0);
        if (ret != 0x80):
            raise IOError, "Didn't succeed"        

    # write 16 bytes to the external EEPROM
    
    def write_eeprom16(self, addr, val):
        self.spi_xfer(COMP_CMD_WREEPROM16)
        self.spi_xfer((addr >> 8) & 0xFF)
        self.spi_xfer(addr & 0xFF)
        x = 0
        while (x != 16):
            self.spi_xfer(val[x])  
            x += 1
            
        ret = self.spi_xfer(0);
        if (ret != 0x80):
            raise IOError, "Didn't succeed"        
    
    # send a command to the SpokePOV
    
    def sendcmd(self, cmd, arg):
        self.spi_xfer(cmd)
        time.sleep(0.005)
        self.spi_xfer(arg)
        time.sleep(0.005)
        ret = self.spi_xfer(0);
        if (ret != 0x80):
            raise IOError, "Didn't succeed"


#---------------------------------------------------------------------------

###################################
# The top-level frame (menus and buttons)
###################################

class SpokeSoftFrame(wx.Frame):

    filename = None
    ed = None
    filemenu = None
    tweakmenu = None
    
    def __init__(self, parent, title):
        global autorotation
        
        # RJW make some arbitrary size
        
        wx.Frame.__init__(self, parent, -1, title,
                          pos=(50, 50), size=(500,630),
                          style=(wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.RESIZE_BOX | wx.MAXIMIZE_BOX)))

        # not quite sure why we do this, but...
        
        self.SetTitle("SpokeCharInterleaved - (Untitled)")
        
        # Create the menubar
        
        menuBar = wx.MenuBar()

        # the file menu 
        
        self.filemenu = wx.Menu()

        # create menu items
        
        self.filemenu.Append(0, "Open...", "Open a caption .txt file")
        self.filemenu.Append(1, "Save", "Save captions")
        self.filemenu.Append(2, "Save As...", "Save into a different file")
        self.filemenu.AppendSeparator()
        self.filemenu.Append(3, "Upload INTERLEAVED Charset", "Transfer charset BMP to SpokePOV")
        self.filemenu.Append(4, "Verify INTERLEAVED Charset", "Check charset BMP vs SpokePOV EEPROM")
        self.filemenu.AppendSeparator()
        self.filemenu.Append(5, "Upload Message", "Upload Message to SpokePOV")
        self.filemenu.AppendSeparator()
        self.filemenu.Append(wx.ID_EXIT, "E&xit", "Exit")

        self.filemenu.Enable(1,False)
        
        # bind to their actions
        
        self.Bind(wx.EVT_MENU, self.OnOpen, id=0)
        self.Bind(wx.EVT_MENU, self.OnSave, id=1)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, id=2)
        self.Bind(wx.EVT_MENU, self.OnUploadButton, id=3)
        self.Bind(wx.EVT_MENU, self.OnVerifyButton, id=4)
        self.Bind(wx.EVT_MENU, self.OnMessageButton, id=5)

        self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
        
        # and put the menu on the menubar
        
        menuBar.Append(self.filemenu, "&File")

        # the tweak menu 
        
        self.tweakmenu = wx.Menu()

        # create menu items
        
        self.tweakmenu.Append(10, "Wrap", "Wrap to 16 characters per line")
        self.tweakmenu.Append(11, "Center", "Center Lines")
       
        # bind to their actions
        
        self.Bind(wx.EVT_MENU, self.OnWrap, id=10)
        self.Bind(wx.EVT_MENU, self.OnCenter, id=11)

        # and put the menu on the menubar
        
        menuBar.Append(self.tweakmenu, "&Tweak")

        self.SetMenuBar(menuBar)

        self.CreateStatusBar()
        
        # create the panel that contains all the UI elements
        
        mainpanel = wx.Panel(self)
        
        mainpanelsizer = wx.BoxSizer(wx.VERTICAL)
        
        self.ed = editor.Editor(mainpanel, -1, style=wx.SUNKEN_BORDER)
        
        mainpanelsizer.Add(self.ed, 1, wx.ALL|wx.GROW, 1)
        mainpanel.SetSizer(mainpanelsizer)
        mainpanel.SetAutoLayout(True)


        self.ed.SetText(["Enter the text",
                    "you want the",
                    "SpokePOV to",
                    "display here.",
                    "",
                    "Keep in mind the",
                    "16 char per line",
                    "limit!"
                   ])
                    
        self.Wrap()
        self.Center()
        
        # create the panel with the UI elements
        
        lowerpanel = wx.Panel(mainpanel)
        lowerpanelsizer = wx.BoxSizer(wx.HORIZONTAL)
        
        # create the panel with the buttons
        
        buttonpanel = wx.Panel(lowerpanel)
        buttonpanelsizer = wx.GridSizer(1, 3, 5, 10)
        

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?