Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 381 lines (330 sloc) 11.722 kb
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
1 #!/usr/bin/env python
2
3 # Copyright 2009 Steve Conklin
4 # steve at conklinhouse dot com
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 import sys
21 import array
22 #import os
23 #import os.path
24 #import string
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
25 from array import *
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
26
27 __version__ = '1.0'
28
29 # Some file location constants
30 initPatternOffset = 0x06DF # programmed patterns start here, grow down
31 currentPatternAddr = 0x07EA # stored in MSN and following byte
32 currentRowAddr = 0x06FF
33 nextRowAddr = 0x072F
34 currentRowNumberAddr = 0x0702
35 carriageStatusAddr = 0x070F
36 selectAddr = 0x07EA
37
38
39
40 # various unknowns which are probably something we care about
41 unknownList = {'0700':0x0700, '0701':0x0701,
42 '0704':0x0704, '0705':0x0705, '0706':0x0706, '0707':0x0707,
43 '0708':0x0708, '0709':0x0709, '070A':0x070A, '070B':0x070B,
44 '070C':0x070C, '070D':0x070D, '070E':0x070E, '0710':0x0710,
45 '0711':0x0711, '0712':0x0712, '0713':0x0713, '0714':0x0714,
46 '0715':0x0715}
47
48 def nibbles(achar):
49 #print '0x%02X' % ord(achar)
50 msn = (ord(achar) & 0xF0) >> 4
51 lsn = ord(achar) & 0x0F
52 return msn, lsn
53
54 def hto(hundreds, tens, ones):
55 return (100 * hundreds) + (10 * tens) + ones
56
57 def roundeven(val):
58 return (val+(val%2))
59
60 def roundeight(val):
61 if val % 8:
62 return val + (8-(val%8))
63 else:
64 return val
65
66 def roundfour(val):
67 if val % 4:
68 return val + (4-(val%4))
69 else:
70 return val
71
72 def nibblesPerRow(stitches):
73 # there are four stitches per nibble
74 # each row is nibble aligned
75 return(roundfour(stitches)/4)
76
77 def bytesPerPattern(stitches, rows):
78 nibbs = rows * nibblesPerRow(stitches)
79 bytes = roundeven(nibbs)/2
80 return bytes
81
82 def bytesForMemo(rows):
83 bytes = roundeven(rows)/2
84 return bytes
85
86 def bytesPerPatternAndMemo(stitches, rows):
87 patbytes = bytesPerPattern(stitches, rows)
88 memobytes = bytesForMemo(rows)
89 return patbytes + memobytes
90
91 class brotherFile(object):
92
93 def __init__(self, fn):
94 self.dfn = None
955f25d Limor "Ladyada" Fried removed some debuggin' stuff
ladyada authored
95 self.verbose = False
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
96 try:
97 try:
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
98 self.df = open(fn, 'rb+') # YOU MUST HAVE BINARY FORMAT!!!
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
99 except IOError:
100 # for now, read only
101 raise
102 #self.df = open(fn, 'w')
103 except:
104 print 'Unable to open brother file <%s>' % fn
105 raise
106 try:
107 self.data = self.df.read(2048)
108 self.df.close()
109 except:
110 print 'Unable to read 2048 bytes from file <%s>' % fn
111 raise
112 self.dfn = fn
113 return
114
115 def __del__(self):
116 return
117
118 def getIndexedByte(self, index):
119 return ord(self.data[index])
120
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
121 def setIndexedByte(self, index, b):
122 # python strings are mutable so we
123 # will convert the string to a char array, poke
124 # and convert back
125 dataarray = array('c')
126 dataarray.fromstring(self.data)
127
2e49e1b Limor "Ladyada" Fried fixed typo
ladyada authored
128 if self.verbose:
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
129 print "* writing ", hex(b), "to", hex(index)
130 #print dataarray
131
132 # this is the actual edit
133 dataarray[index] = chr(b)
134
135 # save the new string. sure its not very memory-efficient
136 # but who cares?
137 self.data = dataarray.tostring()
138
139 # handy for debugging
140 def getFullData(self):
141 return self.data
142
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
143 def getIndexedNibble(self, offset, nibble):
144 # nibbles is zero based
145 bytes = nibble/2
146 m, l = nibbles(self.data[offset-bytes])
147 if nibble % 2:
148 return m
149 else:
150 return l
151
152 def getRowData(self, pattOffset, stitches, rownumber):
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
153 row=array('B')
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
154 nibspr = nibblesPerRow(stitches)
155 startnib = nibspr * rownumber
156 endnib = startnib + nibspr
157
158 for i in range(startnib, endnib, 1):
159 nib = self.getIndexedNibble(pattOffset, i)
160 row.append(nib & 0x01)
161 stitches = stitches - 1
162 if stitches:
163 row.append((nib & 0x02) >> 1)
164 stitches = stitches - 1
165 if stitches:
166 row.append((nib & 0x04) >> 2)
167 stitches = stitches - 1
168 if stitches:
169 row.append((nib & 0x08) >> 3)
170 stitches = stitches - 1
171
172 return row
173
174 def getPatterns(self, patternNumber = None):
175 """
176 Get a list of custom patterns stored in the file, or
177 information for a single pattern.
178 Pattern information is stored at the beginning
179 of the file, with seven bytes per pattern and
180 99 possible patterns, numbered 901-999.
181 Returns: A list of tuples:
182 patternNumber
183 stitches
184 rows
185 patternOffset
186 memoOffset
187 """
188 patlist = []
189 idx = 0
190 pptr = initPatternOffset
191 for pi in range(1, 100):
192 flag = ord(self.data[idx])
193 if self.verbose:
194 print 'Entry %d, flag is 0x%02X' % (pi, flag)
195 idx = idx + 1
196 unknown = ord(self.data[idx])
197 idx = idx + 1
198 rh, rt = nibbles(self.data[idx])
199 idx = idx + 1
200 ro, sh = nibbles(self.data[idx])
201 idx = idx + 1
202 st, so = nibbles(self.data[idx])
203 idx = idx + 1
204 unk, ph = nibbles(self.data[idx])
205 idx = idx + 1
206 pt, po = nibbles(self.data[idx])
207 idx = idx + 1
208 rows = hto(rh,rt,ro)
209 stitches = hto(sh,st,so)
210 patno = hto(ph,pt,po)
211 # we have this entry
212 if self.verbose:
213 print ' Pattern %3d: %3d Rows, %3d Stitches - ' % (patno, rows, stitches)
214 print 'Unk = %d, Unknown = 0x%02X (%d)' % (unk, unknown, unknown)
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
215 if flag != 0:
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
216 # valid entry
217 memoff = pptr
955f25d Limor "Ladyada" Fried removed some debuggin' stuff
ladyada authored
218 if self.verbose:
219 print "Memo #",patno, "offset ", hex(memoff)
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
220 patoff = pptr - bytesForMemo(rows)
955f25d Limor "Ladyada" Fried removed some debuggin' stuff
ladyada authored
221 if self.verbose:
222 print "Pattern #",patno, "offset ", hex(patoff)
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
223 pptr = pptr - bytesPerPatternAndMemo(stitches, rows)
955f25d Limor "Ladyada" Fried removed some debuggin' stuff
ladyada authored
224 if self.verbose:
225 print "Ending offset ", hex(pptr)
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
226 # TODO figure out how to calculate pattern length
227 #pptr = pptr - something
228 if patternNumber:
229 if patternNumber == patno:
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
230 patlist.append({'number':patno, 'stitches':stitches, 'rows':rows, 'memo':memoff, 'pattern':patoff, 'pattend':pptr})
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
231 else:
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
232 patlist.append({'number':patno, 'stitches':stitches, 'rows':rows, 'memo':memoff, 'pattern':patoff, 'pattend':pptr})
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
233 else:
234 break
235 return patlist
236
237 def getMemo(self):
238 """
239 Return an array containing the memo
240 information for the pattern currently in memory
241 """
242 patt = self.patternNumber()
243 if patt > 900:
244 return self.getPatternMemo(patt)
245 else:
246 rows = 0 # TODO XXXXXXXXX
247 return [0]
248
249 def patternNumber(self):
250 sn, pnh = nibbles(self.data[currentPatternAddr])
251 pnt, pno = nibbles(self.data[currentPatternAddr+1])
252 pattern = hto(pnh,pnt,pno)
253 return(pattern)
254
255 def getPatternMemo(self, patternNumber):
256 """
257 Return an array containing the memo
258 information for a custom pattern. The array
259 is the same length as the number of rows
260 in the pattern.
261 """
262 list = self.getPatterns(patternNumber)
263 if len(list) == 0:
264 return None
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
265 memos = array('B')
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
266 memoOff = list[0]['memo']
267 rows = list[0]['rows']
268 memlen = roundeven(rows)/2
269 # memo is padded to en even byte
270 for i in range(memoOff, memoOff-memlen, -1):
271 msn, lsn = nibbles(self.data[i])
272 memos.append(lsn)
273 rows = rows - 1
274 if (rows):
275 memos.append(msn)
276 rows = rows - 1
277 return memos
278
279 def getPattern(self, patternNumber):
280 """
281 Return an array containing the pattern
282 information for a pattern.
283 """
284 list = self.getPatterns(patternNumber)
285 if len(list) == 0:
286 return None
287 pattern = []
288
289 patoff = list[0]['pattern']
290 rows = list[0]['rows']
291 stitches = list[0]['stitches']
292
293 #print 'patoff = 0x%04X' % patoff
294 #print 'rows = ', rows
295 #print 'stitches = ', stitches
296 for i in range(0, rows):
297 arow = self.getRowData(patoff, stitches, i)
298 #print arow
299 pattern.append(arow)
300 return pattern
301
302 def displayPattern(self, patternNumber):
303 """
304 Display a user pattern stored in file saved
305 from the brother knitting machine. Patterns
306 in memory are stored with the beginning of the
307 pattern at the highest memory address.
308 """
309
310 return
311
312 def rowNumber(self):
313 sn, rnh = nibbles(self.data[currentRowNumberAddr])
314 rnt, rno = nibbles(self.data[currentRowNumberAddr+1])
315 rowno = hto(rnh,rnt,rno)
316 return(rowno)
317
318 def nextRow(self):
319 return self.getRowData(nextRowAddr, 200, 0)
320
321 def selectorValue(self):
322 return ord(self.data[selectAddr])
323
324 def carriageStatus(self):
325 return ord(self.data[carriageStatusAddr])
326
327 def motifData(self):
328 motiflist = []
329 addr = 0x07FB
330 for i in range(6):
331 mph, mpt = nibbles(self.data[addr])
332 if mph & 8:
333 mph = mph - 8
334 side = 'right'
335 else:
336 side = 'left'
337 mpo, foo = nibbles(self.data[addr+1])
338 mch, mct = nibbles(self.data[addr+2])
339 mco, bar = nibbles(self.data[addr+3])
340 pos = hto(mph,mpt,mpo)
341 cnt = hto(mch,mct,mco)
342 motiflist.append({'position':pos, 'copies':cnt, 'side':side})
343 addr = addr - 3
344 return motiflist
345
346 def patternPosition(self):
347 addr = 0x07FE
348 foo, ph = nibbles(self.data[addr])
349 if ph & 8:
350 ph = ph - 8
351 side = 'right'
352 else:
353 side = 'left'
354 pt, po = nibbles(self.data[addr+1])
355 pos = hto(ph,pt,po)
356
357 return {'position':pos, 'side':side}
358
359 # these are hardcoded for now
360 def unknownOne(self):
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
361 info = array('B')
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
362 for i in range(0x06E0, 0x06E5):
363 info.append(ord(self.data[i]))
364 return info
365
366 def unknownMemoRange(self):
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
367 info = array('B')
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
368 for i in range(0x0731, 0x0787):
369 info.append(ord(self.data[i]))
370 return info
371
372 def unknownEndRange(self):
47780c8 Limor "Ladyada" Fried added data-manipulation procedure for poking new values into the datafil...
ladyada authored
373 info = array('B')
febe4fc brian initial checkin including test setup for becky's knitting machine and
brianredbeard authored
374 for i in range(0x07D0, 0x07E9):
375 info.append(ord(self.data[i]))
376 return info
377
378 def unknownAddrs(self):
379 return unknownList.items()
380
Something went wrong with that request. Please try again.