OpenCores
URL https://opencores.org/ocsvn/usb_dongle_fpga/usb_dongle_fpga/trunk

Subversion Repositories usb_dongle_fpga

[/] [usb_dongle_fpga/] [tags/] [version_1_5/] [sw/] [dongle.py] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 nuubik
#! /usr/bin/python
2
# -*- coding: utf-8 -*-
3
##########################################################################
4
# LPC Dongle programming software 
5
#
6
# Copyright (C) 2006 Artec Design
7
# 
8
# This library is free software; you can redistribute it and/or
9
# modify it under the terms of the GNU Lesser General Public
10
# License as published by the Free Software Foundation; either
11
# version 2.1 of the License, or (at your option) any later version.
12
# 
13
# This software is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
# Lesser General Public License for more details.
17
 
18
# You should have received a copy of the GNU Lesser General Public
19
# License along with this library; if not, write to the Free Software
20
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
##########################################################################
22
 
23
#-------------------------------------------------------------------------
24
# Project:   LPC Dongle programming software 
25
# Name:      dongle.py
26
# Purpose:   Executable command line tool 
27
#
28
# Author:    Jüri Toomessoo <jyrit@artecdesign.ee>
29
# Copyright: (c) 2006 Artec Design
30
# Licence:   LGPL
31
#
32
# Created:   06 Oct. 2006
33
# History:   12 oct. 2006  Version 1.0 released
34
#            
35
#
36
#-------------------------------------------------------------------------
37
 
38
import os
39
import sys
40
import string
41
import time
42
from sets import *
43
from struct import *
44
from Uspp.uspp import *
45
 
46
#### global funcs ####
47
def usage(s):
48
    print "Artec USB Dongle programming utility"
49
    print "Usage: ",s," -c comport [-fvdq] filename address"
50
    print "       ",s," [-fvdqr] offset length filename"
51
    print "Options:"
52
    print " -c        COM port"
53
    print " -v        Verbose"
54
    print " -f        Forced"
55
    print " -d        Debug"
56
    print " -q        Query"
57
    print " -r        Readback "
58
    print "Examples:"
59
    print ""
60
    print " ",s," -c COM3 loader.bin 0"
61
    print " ",s," -c /dev/ttyS3 content.bin 256K"
62
    print " ",s," -c COM3 device 1M"
63
    print " ",s," -c COM3 -r 0x0000 256 flashcontent.bin"
64
######################
65
 
66
 
67
class DongleMode:
68
    def __init__(self):
69
        self.v = 0
70
        self.f = 0
71
        self.d = 0
72
        self.q = 0
73
        self.r = 0
74
        self.filename=""
75
        self.portname=""
76
        self.address=-1
77
        self.offset=-1
78
        self.length=-1
79
 
80
    def convParamStr(self,param):
81
        mult = 1
82
        value = 0
83
        str = param
84
        if str.find("K")>-1:
85
            mult = 1024
86
            str=str.strip("K")
87
        if str.find("M")>-1:
88
            mult = 1024*1024
89
            str=str.strip("M")
90
        try:
91
            if str.find("x")>-1:
92
                value = int(str,0)*mult  #conver hex string to int
93
            else:
94
                value = int(str)*mult  #conver demical string to int
95
        except ValueError:
96
            print "Bad parameter format given for: ",param
97
 
98
        return value
99
 
100
 
101
 
102
 
103
class Dongle:
104
    def __init__(self,name, baud, timeout):  #time out in millis 1000 = 1s baud like 9600, 57600
105
        try:
106
            self.tty = SerialPort(name,timeout, baud)
107
        except:
108
            print "Unable to open port"
109
            sys.exit();
110
 
111
    def getReturn(self,byteCount):
112
        i=0
113
        while don.tty.inWaiting()<byteCount:
114
            i=i+1
115
            if i==10000*byteCount:
116
                break
117
        if i==10000*byteCount:
118
            print "Dongle not connected to port or not communicating"
119
            sys.exit()
120
        return don.tty.read(byteCount)  ## ret two bytes
121
 
122
    def write_command(self,command):
123
        lsb = command&0xff
124
        msb = (command>>8)&0xff
125
        self.tty.write_2bytes(msb,lsb)
126
 
127
    def get_address_buf(self,address):  #set word address
128
        lsbyte = address&0xff
129
        byte = (address>>8)&0xff
130
        msbyte = (address>>16)&0xff
131
        buffer = ""
132
        buffer += chr(lsbyte)
133
        buffer += chr(0xA0)
134
        buffer +=  chr(byte)
135
        buffer +=  chr(0xA1)
136
        buffer +=  chr(msbyte)
137
        buffer +=  chr(0xA2)
138
        evaluate = (address>>24)
139
        if evaluate != 0:
140
            print "Addressign fault. Too large address passed"
141
            sys.exit()
142
        return buffer
143
 
144
 
145
    def set_address(self,address):  #set word address
146
        lsbyte = address&0xff
147
        byte = (address>>8)&0xff
148
        msbyte = (address>>16)&0xff
149
        evaluate = (address>>24)
150
        if evaluate != 0:
151
            print "Addressign fault. Too large address passed"
152
            sys.exit()
153
        self.tty.write_2bytes(lsbyte,0xA0)            #set internal address to dongle
154
        self.tty.write_2bytes(byte,0xA1)            #set internal address to dongle
155
        self.tty.write_2bytes(msbyte,0xA2)            #send query command
156
 
157
    def read_data(self,wordCount,address):
158
        command = 0
159
        byteCount = wordCount<<1  #calc byte count
160
        if wordCount>0 :
161
            command = (command|wordCount)<<8;
162
            command = command|0xCD
163
            self.set_address(address)    # send read address
164
            self.write_command(command)  # send get data command
165
            return self.getReturn(byteCount)
166
        else:
167
            print "Word count can't be under 1"
168
            sys.exit()
169
 
170
    def read_status(self):
171
        don.write_command(0x0070) # 0x0098 //clear status
172
        command = 0
173
        wordCount= 1  #calc byte count
174
        byteCount = wordCount<<1
175
        command = (command|wordCount)<<8;
176
        command = command|0xCD
177
        self.write_command(command)  # send get data command
178
        return self.getReturn(byteCount)
179
 
180
 
181
    def get_block_no(self,address):
182
        return address >> 16 # 16 bit mode block is 64Kwords
183
 
184
    def wait_on_busy(self):
185
        exit=0
186
        while exit==0:
187
            buf=self.read_status()
188
            statReg = ord(buf[0])  #8 bit reg
189
            if statReg>>7 == 1:
190
                exit=1
191
 
192
    def parse_status(self):  # use only after wait on busy commad to get result of the operation
193
        exit = 0
194
        buf=self.read_status()
195
        statReg = ord(buf[0])  #8 bit reg
196
        if (statReg>>5)&1 == 1:
197
            print "Block erase suspended"
198
            exit = 1
199
        if (statReg>>4)&3 == 3:
200
            print "Error in command order"  #if bits 4 and 5 are set then 
201
            exit = 1
202
        if (statReg>>4)&3 == 1:
203
            print "Error in setting lock bit"
204
            exit = 1
205
        if (statReg>>3)&1 == 1:
206
            print "Low Programming Voltage Detected, Operation Aborted"
207
            exit = 1
208
        if (statReg>>2)&1 == 1:
209
            print "Programming suspended"
210
            exit = 1
211
        if (statReg>>1)&1 == 1:
212
            print "Block lock bit detected"
213
            exit = 1
214
        if exit == 1:
215
            sys.exit()
216
 
217
    def erase_block(self,blockNo):
218
        blockAddress = blockNo << 16
219
        command = 0x0020
220
        self.set_address(blockAddress)
221
        self.write_command(command)  #issue block erase
222
        command = 0x00D0
223
        self.write_command(command)  #issue block erase confirm
224
        self.wait_on_busy()
225
        self.parse_status()
226
 
227
    def buffer_write(self,wordCount,startAddress,buffer):
228
        # to speed up buffer writing compose all commands into one buffer
229
        # instead of multiple single writes this is needed as the FTDI chip
230
        # round lag is amazingly large with VCOM drivers
231
        #u = len(buffer)
232
        if len(buffer)<32:            #don't ever make unaligned writes
233
            i=len(buffer)
234
            while len(buffer)<32:
235
                buffer += "\xff"
236
        adrBuf = self.get_address_buf(startAddress)   #6 bytes total
237
        cmd_e8=""  #8 bytes total
238
        cmd_e8+= chr(16)   #make it always 16 wordCount
239
        cmd_e8+= chr(0xE8)
240
        cmd_wcnt=""  #10 bytes total
241
        cmd_wcnt+= chr(0x00)
242
        cmd_wcnt+= chr(16-1)
243
        cmd_buf=""  #12 bytes total
244
        cmd_buf+= chr(0x00)
245
        cmd_buf+= chr(0xD0)
246
        wr_buffer_cmd = adrBuf + cmd_e8 + cmd_wcnt + buffer + cmd_buf   #44 bytes total
247
        self.tty.write_buf_cmd(wr_buffer_cmd)
248
        # no wait needad as the FTDI chip is so slow
249
 
250
 
251
################## Main program #########################
252
 
253
 
254
last_ops = 0
255
mode = DongleMode()
256
# PARSE ARGUMENTS 
257
for arg in sys.argv:
258
    if len(sys.argv) == 1: # if no arguments display help
259
       usage(sys.argv[0])
260
       sys.exit()
261
    if arg in ("-h","--help","/help","/h"):
262
        usage(sys.argv[0])
263
        sys.exit()
264
    if arg in ("-c"):
265
        last_ops = sys.argv.index(arg) + 1  #if remains last set of options from here start ordered strings
266
        i = sys.argv.index(arg)
267
        print "Opening port: "+sys.argv[i+1]
268
        mode.portname = sys.argv[i+1]   # next element after -c open port for usage
269
    if arg[0]=="-" and arg[1]!="c": # if other opptions
270
        # parse all options in this
271
        last_ops = sys.argv.index(arg)  #if remains last set of options from here start ordered strings
272
        ops = arg[1:]# get all besides the - sign
273
        for op in ops:
274
            if op=="q":
275
                mode.q = 1
276
            if op=="v":
277
                mode.v = 1
278
            if op=="f":
279
                mode.f = 1
280
            if op=="d":
281
                mode.d = 1
282
            if op=="r":
283
                mode.r = 1
284
    else:
285
        i = sys.argv.index(arg)
286
        if i ==  last_ops + 1:
287
            if mode.r==1:
288
                mode.offset=mode.convParamStr(arg)
289
            else:
290
                mode.filename=arg
291
        if i ==  last_ops + 2:
292
            if mode.r==1:
293
                mode.length=mode.convParamStr(arg)
294
            else:
295
                mode.address=mode.convParamStr(arg)
296
 
297
        if i ==  last_ops + 3:
298
            if mode.r==1:
299
                mode.filename=arg
300
            else:
301
                print "Too many parameters provided"
302
                sys.exit()
303
        if i >  last_ops + 3:
304
             print "Too many parameters provided"
305
             sys.exit()
306
 
307
# END PARSE ARGUMENTS             
308
 
309
if mode.portname=="":
310
    print "No port name given see -h for help"
311
    sys.exit()
312
else:
313
    # test PC speed to find sutable delay for linux driver
314
    # to get 250 us 
315
    mytime = time.clock()
316
    n = 0
317
    while (n < 100000):
318
        n += 1;
319
    k10Time = time.clock() - mytime   # time per 10000 while cycles
320
    wait = k10Time/100000.0     # time per while cycle
321
    wait = (0.00025/wait) * 1.20   # count for 250us + safe margin
322
 
323
    # ok done
324
    don = Dongle(mode.portname,115200,100)
325
    print wait
326
    don.tty.wait = wait
327
    don.write_command(0x0050) # 0x0098
328
    don.write_command(0x00C5)            #send dongle check internal command
329
    buf=don.getReturn(2)  # two bytes expected to this command
330
    if ord(buf[1])==0x32 and  ord(buf[0])==0x10:
331
        print "Dongle OK"
332
    else:
333
        print 'Dongle returned on open: %02x %02x '%(ord(buf[1]), ord(buf[0]))
334
 
335
 
336
if mode.q == 1:   # perform a query from dongle
337
    don.write_command(0x0050) # 0x0098
338
    don.write_command(0x0098) # 0x0098
339
    buf=don.read_data(3,0x000010)  # word count and word address
340
    if ord(buf[0])==0x51 and  ord(buf[2])==0x52 and  ord(buf[4])==0x59:
341
        buf=don.read_data(2,0x000000)  # word count and word address
342
        print 'Query  OK, Factory: 0x%02x device: 0x%02x '%(ord(buf[0]),ord(buf[2]))
343
        buf=don.read_data(2,0x000002)
344
        print 'lock bit is 0x%02x 0x%02x'%(ord(buf[0]),ord(buf[1]))
345
    else:
346
        print "Got bad query data:"
347
        print 'Query address 0x10 = 0x%02x%02x '%(ord(buf[1]),ord(buf[0]))
348
        print 'Query address 0x10 = 0x%02x%02x '%(ord(buf[3]),ord(buf[2]))
349
        print 'Query address 0x10 = 0x%02x%02x '%(ord(buf[5]),ord(buf[4]))
350
        print "Read byte count:",len(buf)
351
 
352
    don.write_command(0x00FF) # 0x0098
353
    buf=don.read_data(4,0xff57c0>>1)  # word count and word address     
354
    print 'Data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x '%(ord(buf[1]),ord(buf[0]),ord(buf[3]),ord(buf[2]),ord(buf[5]),ord(buf[4]),ord(buf[7]),ord(buf[6]) )
355
 
356
 
357
 
358
if mode.filename!="" and mode.address!=-1:
359
    #Calculate number of blocks and start of blocks
360
    size = 0
361
    mode.address = mode.address>>1  #make word address
362
    try:
363
        f=open(mode.filename,"rb")
364
        f.seek(0,2) #seek to end
365
        size = f.tell()
366
        f.seek(0) #seek to start
367
        print 'File size %iK '%(size/1024)
368
        f.close()
369
    except IOError:
370
         print "IO Error on file open"
371
         sys.exit()
372
    #clear blockLock bits
373
    don.write_command(0x0060) # 0x0098
374
    don.write_command(0x00D0) # 0x0098
375
    don.wait_on_busy()
376
    don.parse_status()
377
    wordSize = (size+ (size&1))>> 1    # round byte count up and make word address
378
    endBlock = don.get_block_no(mode.address+wordSize - 1)
379
    startBlock = don.get_block_no(mode.address)
380
    i=startBlock
381
    while i <= endBlock:
382
        print 'Erasing block %i '%(i)
383
        don.erase_block(i)
384
        don.wait_on_busy()
385
        don.parse_status()   #do this after programming all but uneaven ending
386
        i=i+1
387
    #don.write_command(0x00FF) # 0x0098
388
    #buf=don.read_data(4,0x000000)  # word count and word address     
389
    #print 'Data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x '%(ord(buf[0]),ord(buf[1]),ord(buf[2]),ord(buf[3]),ord(buf[4]),ord(buf[5]),ord(buf[6]),ord(buf[7]) )
390
 
391
    f=open(mode.filename,"rb")
392
    f.seek(0) #seek to start
393
    address= mode.address
394
    #don.set_address(address)
395
    while 1:
396
        if address/(1024*16) != (address-16)/(1024*16):  # get bytes from words if 512
397
            print 'Progress: %iK of %iK at 0x%06x'%((address-mode.address)/512,size/1024,address)
398
        buf = f.read(32)  #16 words is maximum write here bytes are read
399
        if len(buf)==32:
400
            don.buffer_write(16,address,buf)
401
            address = address + 16
402
        elif len(buf)>0:
403
            don.parse_status()   #do this after programming all but uneaven ending
404
            print "Doing an unaligned write..."
405
            length = len(buf)
406
            length = (length + (length&1))>> 1   #round up to get even word count
407
            buf = buf+"\xff"   #pad just in case rounding took place
408
            don.buffer_write(len,address,buf)
409
            address = address + 16     #inc word address
410
            break
411
        else:
412
            break
413
    print "Write DONE!"
414
    don.parse_status()   #do this after programming all but uneaven ending
415
    f.close()
416
 
417
if mode.r == 1:   # perform a readback
418
    if mode.offset!=-1 and mode.length!=-1 and mode.filename!="":
419
        mode.offset=mode.offset>>1    #make word offset
420
        mode.length= mode.length>>1   #make word length
421
        try:
422
            f=open(mode.filename,"wb")
423
            don.write_command(0x00FF) #  put flash to data read mode
424
            address = mode.offset    # set word address
425
            while 1:
426
                if address/(1024*32) != (address-128)/(1024*32):  # get K bytes from words if 512
427
                    print 'Progress: %iK of %iK'%((address-mode.offset)/512,mode.length/512)
428
                buf=don.read_data(128,address)  # word count and byte address read 64 words to speed up
429
                f.write(buf)
430
                #print "from address:",address<<1," ", len(buf)
431
                if address+128 >= (mode.offset + mode.length):  # 2+64 estimates the end to end in right place
432
                    break
433
                address = address + 128    #this is word address
434
            f.close()
435
            print "Readback done!"
436
        except IOError:
437
            print "IO Error on file open"
438
            sys.exit()
439
    else:
440
       print "Some of readback parameters missing..."
441
       print mode.offset,mode.length, mode.filename
442
       sys.exit()
443
 
444
##########################################################

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.