📄 spokechar.py
字号:
#!/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("SpokeChar - SpokePOV Character Set Utility - (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 Charset", "Transfer charset BMP to SpokePOV")
self.filemenu.Append(4, "Verify 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()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -