Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 353 lines (307 sloc) 10.76 kb
febe4fc @brianredbeard initial checkin including test setup for becky's knitting machine and
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
25 #from array import *
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
95 self.verbose = False
96 try:
97 try:
98 self.df = open(fn, 'r+')
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
121 def getIndexedNibble(self, offset, nibble):
122 # nibbles is zero based
123 bytes = nibble/2
124 m, l = nibbles(self.data[offset-bytes])
125 if nibble % 2:
126 return m
127 else:
128 return l
129
130 def getRowData(self, pattOffset, stitches, rownumber):
131 row=array.array('B')
132 nibspr = nibblesPerRow(stitches)
133 startnib = nibspr * rownumber
134 endnib = startnib + nibspr
135
136 for i in range(startnib, endnib, 1):
137 nib = self.getIndexedNibble(pattOffset, i)
138 row.append(nib & 0x01)
139 stitches = stitches - 1
140 if stitches:
141 row.append((nib & 0x02) >> 1)
142 stitches = stitches - 1
143 if stitches:
144 row.append((nib & 0x04) >> 2)
145 stitches = stitches - 1
146 if stitches:
147 row.append((nib & 0x08) >> 3)
148 stitches = stitches - 1
149
150 return row
151
152 def getPatterns(self, patternNumber = None):
153 """
154 Get a list of custom patterns stored in the file, or
155 information for a single pattern.
156 Pattern information is stored at the beginning
157 of the file, with seven bytes per pattern and
158 99 possible patterns, numbered 901-999.
159 Returns: A list of tuples:
160 patternNumber
161 stitches
162 rows
163 patternOffset
164 memoOffset
165 """
166 patlist = []
167 idx = 0
168 pptr = initPatternOffset
169 for pi in range(1, 100):
170 flag = ord(self.data[idx])
171 if self.verbose:
172 print 'Entry %d, flag is 0x%02X' % (pi, flag)
173 idx = idx + 1
174 unknown = ord(self.data[idx])
175 idx = idx + 1
176 rh, rt = nibbles(self.data[idx])
177 idx = idx + 1
178 ro, sh = nibbles(self.data[idx])
179 idx = idx + 1
180 st, so = nibbles(self.data[idx])
181 idx = idx + 1
182 unk, ph = nibbles(self.data[idx])
183 idx = idx + 1
184 pt, po = nibbles(self.data[idx])
185 idx = idx + 1
186 rows = hto(rh,rt,ro)
187 stitches = hto(sh,st,so)
188 patno = hto(ph,pt,po)
189 # we have this entry
190 if self.verbose:
191 print ' Pattern %3d: %3d Rows, %3d Stitches - ' % (patno, rows, stitches)
192 print 'Unk = %d, Unknown = 0x%02X (%d)' % (unk, unknown, unknown)
193 if flag == 1:
194 # valid entry
195 memoff = pptr
196 patoff = pptr - bytesForMemo(rows)
197 pptr = pptr - bytesPerPatternAndMemo(stitches, rows)
198 # TODO figure out how to calculate pattern length
199 #pptr = pptr - something
200 if patternNumber:
201 if patternNumber == patno:
202 patlist.append({'number':patno, 'stitches':stitches, 'rows':rows, 'memo':memoff, 'pattern':patoff})
203 else:
204 patlist.append({'number':patno, 'stitches':stitches, 'rows':rows, 'memo':memoff, 'pattern':patoff})
205 else:
206 break
207 return patlist
208
209 def getMemo(self):
210 """
211 Return an array containing the memo
212 information for the pattern currently in memory
213 """
214 patt = self.patternNumber()
215 if patt > 900:
216 return self.getPatternMemo(patt)
217 else:
218 rows = 0 # TODO XXXXXXXXX
219 return [0]
220
221 def patternNumber(self):
222 sn, pnh = nibbles(self.data[currentPatternAddr])
223 pnt, pno = nibbles(self.data[currentPatternAddr+1])
224 pattern = hto(pnh,pnt,pno)
225 return(pattern)
226
227 def getPatternMemo(self, patternNumber):
228 """
229 Return an array containing the memo
230 information for a custom pattern. The array
231 is the same length as the number of rows
232 in the pattern.
233 """
234 list = self.getPatterns(patternNumber)
235 if len(list) == 0:
236 return None
237 memos = array.array('B')
238 memoOff = list[0]['memo']
239 rows = list[0]['rows']
240 memlen = roundeven(rows)/2
241 # memo is padded to en even byte
242 for i in range(memoOff, memoOff-memlen, -1):
243 msn, lsn = nibbles(self.data[i])
244 memos.append(lsn)
245 rows = rows - 1
246 if (rows):
247 memos.append(msn)
248 rows = rows - 1
249 return memos
250
251 def getPattern(self, patternNumber):
252 """
253 Return an array containing the pattern
254 information for a pattern.
255 """
256 list = self.getPatterns(patternNumber)
257 if len(list) == 0:
258 return None
259 pattern = []
260
261 patoff = list[0]['pattern']
262 rows = list[0]['rows']
263 stitches = list[0]['stitches']
264
265 #print 'patoff = 0x%04X' % patoff
266 #print 'rows = ', rows
267 #print 'stitches = ', stitches
268 for i in range(0, rows):
269 arow = self.getRowData(patoff, stitches, i)
270 #print arow
271 pattern.append(arow)
272 return pattern
273
274 def displayPattern(self, patternNumber):
275 """
276 Display a user pattern stored in file saved
277 from the brother knitting machine. Patterns
278 in memory are stored with the beginning of the
279 pattern at the highest memory address.
280 """
281
282 return
283
284 def rowNumber(self):
285 sn, rnh = nibbles(self.data[currentRowNumberAddr])
286 rnt, rno = nibbles(self.data[currentRowNumberAddr+1])
287 rowno = hto(rnh,rnt,rno)
288 return(rowno)
289
290 def nextRow(self):
291 return self.getRowData(nextRowAddr, 200, 0)
292
293 def selectorValue(self):
294 return ord(self.data[selectAddr])
295
296 def carriageStatus(self):
297 return ord(self.data[carriageStatusAddr])
298
299 def motifData(self):
300 motiflist = []
301 addr = 0x07FB
302 for i in range(6):
303 mph, mpt = nibbles(self.data[addr])
304 if mph & 8:
305 mph = mph - 8
306 side = 'right'
307 else:
308 side = 'left'
309 mpo, foo = nibbles(self.data[addr+1])
310 mch, mct = nibbles(self.data[addr+2])
311 mco, bar = nibbles(self.data[addr+3])
312 pos = hto(mph,mpt,mpo)
313 cnt = hto(mch,mct,mco)
314 motiflist.append({'position':pos, 'copies':cnt, 'side':side})
315 addr = addr - 3
316 return motiflist
317
318 def patternPosition(self):
319 addr = 0x07FE
320 foo, ph = nibbles(self.data[addr])
321 if ph & 8:
322 ph = ph - 8
323 side = 'right'
324 else:
325 side = 'left'
326 pt, po = nibbles(self.data[addr+1])
327 pos = hto(ph,pt,po)
328
329 return {'position':pos, 'side':side}
330
331 # these are hardcoded for now
332 def unknownOne(self):
333 info = array.array('B')
334 for i in range(0x06E0, 0x06E5):
335 info.append(ord(self.data[i]))
336 return info
337
338 def unknownMemoRange(self):
339 info = array.array('B')
340 for i in range(0x0731, 0x0787):
341 info.append(ord(self.data[i]))
342 return info
343
344 def unknownEndRange(self):
345 info = array.array('B')
346 for i in range(0x07D0, 0x07E9):
347 info.append(ord(self.data[i]))
348 return info
349
350 def unknownAddrs(self):
351 return unknownList.items()
352
Something went wrong with that request. Please try again.