Statistics
| Branch: | Tag: | Revision:

root / host / utils / usrp_n2xx_net_burner.py @ 4b637f3e

History | View | Annotate | Download (10.7 KB)

1
#!/usr/bin/env python
2
#
3
# Copyright 2010 Ettus Research LLC
4
#
5
# This program is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
#
18

    
19
# TODO: make it autodetect UHD devices
20
# TODO: you should probably watch sequence numbers
21

    
22
import optparse
23
import math
24
import os
25
import re
26
import struct
27
import socket
28
import sys
29

    
30
########################################################################
31
# constants
32
########################################################################
33
UDP_FW_UPDATE_PORT = 49154
34
UDP_MAX_XFER_BYTES = 1024
35
UDP_TIMEOUT = 3
36
UDP_POLL_INTERVAL = 0.10 #in seconds
37

    
38
USRP2_FW_PROTO_VERSION = 7
39

    
40
#from bootloader_utils.h
41

    
42
FPGA_IMAGE_SIZE_BYTES = 1572864
43
FW_IMAGE_SIZE_BYTES = 31744
44
SAFE_FPGA_IMAGE_LOCATION_ADDR = 0x00000000
45
SAFE_FW_IMAGE_LOCATION_ADDR = 0x003F0000
46
PROD_FPGA_IMAGE_LOCATION_ADDR = 0x00180000
47
PROD_FW_IMAGE_LOCATION_ADDR = 0x00300000
48

    
49
FLASH_DATA_PACKET_SIZE = 256
50

    
51
#see fw_common.h
52
FLASH_ARGS_FMT = '!LLLLL256s'
53
FLASH_INFO_FMT = '!LLLLL256x'
54
FLASH_IP_FMT =   '!LLLL260x'
55

    
56
class update_id_t:
57
  USRP2_FW_UPDATE_ID_WAT = ord(' ')
58
  USRP2_FW_UPDATE_ID_OHAI_LOL = ord('a')
59
  USRP2_FW_UPDATE_ID_OHAI_OMG = ord('A')
60
  USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL = ord('f')
61
  USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG = ord('F')
62
  USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL = ord('e')
63
  USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG = ord('E')
64
  USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL = ord('d')
65
  USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG = ord('D')
66
  USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG = ord('B')
67
  USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL = ord('w')
68
  USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG = ord('W')
69
  USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL = ord('r')
70
  USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG = ord('R')
71
  USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL = ord('s')
72
  USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG = ord('S')
73
  USRP2_FW_UPDATE_ID_KTHXBAI = ord('~')
74

    
75
_seq = -1
76
def seq():
77
  global _seq
78
  _seq = _seq+1
79
  return _seq 
80

    
81
########################################################################
82
# helper functions
83
########################################################################
84
def unpack_flash_args_fmt(s):
85
  return struct.unpack(FLASH_ARGS_FMT, s) #(proto_ver, pktid, seq, flash_addr, length, data)
86

    
87
def unpack_flash_info_fmt(s):
88
  return struct.unpack(FLASH_INFO_FMT, s) #(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
89

    
90
def unpack_flash_ip_fmt(s):
91
  return struct.unpack(FLASH_IP_FMT, s) #(proto_ver, pktid, seq, ip_addr)
92

    
93
def pack_flash_args_fmt(proto_ver, pktid, seq, flash_addr, length, data):
94
  return struct.pack(FLASH_ARGS_FMT, proto_ver, pktid, seq, flash_addr, length, data)
95

    
96
def pack_flash_info_fmt(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes):
97
  return struct.pack(FLASH_INFO_FMT, proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
98

    
99
def send_and_recv(pkt, ip):
100
  update_socket = create_socket()
101

    
102
  try:
103
    update_socket.sendto(pkt, (ip, UDP_FW_UPDATE_PORT))
104
  except Exception, e: 
105
    print e
106
    sys.exit(1)
107

    
108
  try:
109
    (recv_pkt, recv_addr) = update_socket.recvfrom(UDP_MAX_XFER_BYTES)
110
  except Exception, e: 
111
    print e
112
    sys.exit(1)
113

    
114
  if recv_addr != (options.ip, UDP_FW_UPDATE_PORT):
115
    raise Exception, "Packet received from invalid IP %s, expected %s" % (recv_addr, options.ip)
116

    
117
  return recv_pkt
118

    
119
def create_socket():
120
  socket.setdefaulttimeout(UDP_TIMEOUT)
121
  update_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
122
  return update_socket
123

    
124
#just here to validate comms
125
def init_update(ip):
126
  out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0, "")
127
  in_pkt = send_and_recv(out_pkt, ip)
128
  (proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(in_pkt)
129
  if pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG:
130
    print "USRP2P found."
131
  else:
132
    raise Exception, "Invalid reply received from device."
133

    
134
#  print "Incoming:\n\tVer: %i\n\tID: %c\n\tSeq: %i\n\tIP: %i\n" % (proto_ver, chr(pktid), rxseq, ip_addr)
135

    
136
def get_flash_info(ip):
137
  out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL, seq(), 0, 0, "")
138
  in_pkt = send_and_recv(out_pkt, ip)
139

    
140
  (proto_ver, pktid, rxseq, sector_size_bytes, memory_size_bytes) = unpack_flash_info_fmt(in_pkt)
141

    
142
  if pktid != update_id_t.USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG:
143
    raise Exception, "Invalid reply %c from device." % (chr(pktid))
144

    
145

    
146
  return (memory_size_bytes, sector_size_bytes)
147

    
148
def burn_fw(ip, fw, fpga, reset, safe):
149
  init_update(ip)
150
  (flash_size, sector_size) = get_flash_info(ip)
151

    
152
  print "Flash size: %i\nSector size: %i" % (flash_size, sector_size)
153

    
154
  if fpga:
155
    if safe:
156
        image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR
157
    else:
158
        image_location = PROD_FPGA_IMAGE_LOCATION_ADDR
159
    
160
    fpga_file = open(fpga, 'rb')
161
    fpga_image = fpga_file.read()
162
    erase_image(ip, image_location, FPGA_IMAGE_SIZE_BYTES)
163
    write_image(ip, fpga_image, image_location)
164
    verify_image(ip, fpga_image, image_location)
165

    
166
  if fw:
167
    if safe:
168
        image_location = SAFE_FW_IMAGE_LOCATION_ADDR
169
    else:
170
        image_location = PROD_FW_IMAGE_LOCATION_ADDR
171
        
172
    fw_file = open(fw, 'rb')
173
    fw_image = fw_file.read()
174
    erase_image(ip, image_location, FW_IMAGE_SIZE_BYTES)
175
    write_image(ip, fw_image, image_location)
176
    verify_image(ip, fw_image, image_location)
177
    
178
  if reset:
179
    reset_usrp(ip)
180

    
181
def write_image(ip, image, addr):
182
  print "Writing image"
183
#we split the image into smaller (256B) bits and send them down the wire
184
  while image:
185
    out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL, seq(), addr, FLASH_DATA_PACKET_SIZE, image[:FLASH_DATA_PACKET_SIZE])
186
    in_pkt = send_and_recv(out_pkt, ip)
187

    
188
    (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
189

    
190
    if pktid != update_id_t.USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG:
191
      raise Exception, "Invalid reply %c from device." % (chr(pktid))
192

    
193
    image = image[FLASH_DATA_PACKET_SIZE:]
194
    addr += FLASH_DATA_PACKET_SIZE
195

    
196
def verify_image(ip, image, addr):
197
  print "Verifying data"
198
  readsize = len(image)
199
  readdata = str()
200
  while readsize > 0:
201
    if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize
202
    else: thisreadsize = FLASH_DATA_PACKET_SIZE
203
    out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize, "")
204
    in_pkt = send_and_recv(out_pkt, ip)
205
    
206
    (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
207

    
208
    if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG:
209
      raise Exception, "Invalid reply %c from device." % (chr(pktid))
210

    
211
    readdata += data[:thisreadsize]
212
    readsize -= FLASH_DATA_PACKET_SIZE
213
    addr += FLASH_DATA_PACKET_SIZE
214

    
215
  print "Read back %i bytes" % len(readdata)
216
#  print readdata
217

    
218
#  for i in range(256, 512):
219
#    print "out: %i in: %i" % (ord(image[i]), ord(readdata[i]))
220

    
221
  if readdata != image:
222
    print "Verify failed. Image did not write correctly."
223
  else:
224
    print "Success."
225
    
226
def reset_usrp(ip):
227
    out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL, seq(), 0, 0, "")
228
    in_pkt = send_and_recv(out_pkt, ip)
229
    
230
    (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
231
    if pktid == update_id_t.USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG:
232
        raise Exception, "Device failed to reset."
233

    
234
def erase_image(ip, addr, length):
235
  #get flash info first
236
  out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL, seq(), addr, length, "")
237
  in_pkt = send_and_recv(out_pkt, ip)
238

    
239
  (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
240

    
241
  if pktid != update_id_t.USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG:
242
    raise Exception, "Invalid reply %c from device." % (chr(pktid))
243

    
244
  print "Erasing %i bytes at %i" % (length, addr)
245

    
246
  #now wait for it to finish
247
  while(1):
248
    out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL, seq(), 0, 0, "")
249
    in_pkt = send_and_recv(out_pkt, ip)
250

    
251
    (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt)
252

    
253
    if pktid == update_id_t.USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG: break
254
    elif pktid != update_id_t.USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG:
255
      raise Exception, "Invalid reply %c from device." % (chr(pktid))
256

    
257

    
258
########################################################################
259
# command line options
260
########################################################################
261
def get_options():
262
    parser = optparse.OptionParser()
263
    parser.add_option("--ip",   type="string",                 help="USRP2P firmware address",        default='')
264
    parser.add_option("--fw",   type="string",                 help="firmware image path (optional)", default='')
265
    parser.add_option("--fpga", type="string",                 help="fpga image path (optional)",     default='')
266
    parser.add_option("--reset", action="store_true",          help="reset the device after writing", default=False)
267
    parser.add_option("--overwrite-safe", action="store_true", help="never ever use this option", default=False)
268
    (options, args) = parser.parse_args()
269

    
270
    return options
271

    
272
########################################################################
273
# main
274
########################################################################
275
if __name__=='__main__':
276
    options = get_options()
277
    if not options.ip: raise Exception, 'no ip address specified'
278

    
279
    if not options.fpga and not options.fw and not options.reset: raise Exception, 'Must specify either a firmware image or FPGA image, and/or reset.'
280
    
281
    if options.overwrite_safe:
282
        print("Are you REALLY, REALLY sure you want to overwrite the safe image? This is ALMOST ALWAYS a terrible idea.")
283
        print("If your image is faulty, your USRP2+ will become a brick until reprogrammed via JTAG.")
284
        response = raw_input("""Type "yes" to continue, or anything else to quit: """)
285
        if response != "yes":
286
            sys.exit(0)
287
    
288
    burn_fw(ip=options.ip, fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe)