Python Script for CC2650 BSL
[i3-mote/i3-mote.git] / Basic-Test-Package / BSL / CC2650 / cc2650-bsl.py
1 #!/usr/bin/env python
3 # Copyright (c) 2014, Jelmer Tiete <jelmer@tiete.be>.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 # 3. The name of the author may not be used to endorse or promote
15 #    products derived from this software without specific prior
16 #    written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 # Implementation based on stm32loader by Ivan A-R <ivan@tuxotronic.org>
32 # Serial boot loader over UART for CC13xx / CC2538 / CC26xx
33 # Based on the info found in TI's swru333a.pdf (spma029.pdf)
34 #
35 # Bootloader only starts if no valid image is found or if boot loader
36 # backdoor is enabled.
37 # Make sure you don't lock yourself out!! (enable backdoor in your firmware)
38 # More info at https://github.com/JelmerT/cc2538-bsl
40 from __future__ import print_function
41 from subprocess import Popen, PIPE
43 import sys, getopt
44 import glob
45 import time
46 import tempfile
47 import os
48 import subprocess
49 import struct
50 import binascii
51 import traceback
53 try:
54     import magic
55     have_magic = True
56 except ImportError:
57     have_magic = False
59 try:
60     from intelhex import IntelHex
61     have_hex_support = True
62 except ImportError:
63     have_hex_support = False
65 #version
66 VERSION_STRING = "2.1"
68 # Verbose level
69 QUIET = 5
71 # Check which version of Python is running
72 PY3 = sys.version_info >= (3,0)
74 try:
75     import serial
76 except ImportError:
77     print('{} requires the Python serial library'.format(sys.argv[0]))
78     print('Please install it with one of the following:')
79     print('')
80     if PY3:
81         print('   Ubuntu:  sudo apt-get install python3-serial')
82         print('   Mac:     sudo port install py34-serial')
83     else:
84         print('   Ubuntu:  sudo apt-get install python-serial')
85         print('   Mac:     sudo port install py-serial')
86     sys.exit(1)
89 def mdebug(level, message, attr='\n'):
90     if QUIET >= level:
91         print(message, end=attr, file=sys.stderr)
93 # Takes chip IDs (obtained via Get ID command) to human-readable names
94 CHIP_ID_STRS = {0xb964: 'CC2538'}
96 RETURN_CMD_STRS =  {0x40: 'Success',
97                     0x41: 'Unknown command',
98                     0x42: 'Invalid command',
99                     0x43: 'Invalid address',
100                     0x44: 'Flash fail'
101                     }
103 COMMAND_RET_SUCCESS = 0x40
104 COMMAND_RET_UNKNOWN_CMD = 0x41
105 COMMAND_RET_INVALID_CMD = 0x42
106 COMMAND_RET_INVALID_ADR = 0x43
107 COMMAND_RET_FLASH_FAIL = 0x44
109 class CmdException(Exception):
110     pass
112 class FirmwareFile(object):
113     HEX_FILE_EXTENSIONS = ('hex', 'ihx', 'ihex')
115     def __init__(self, path):
116         """
117         Read a firmware file and store its data ready for device programming.
119         This class will try to guess the file type if python-magic is available.
121         If python-magic indicates a plain text file, and if IntelHex is
122         available, then the file will be treated as one of Intel HEX format.
124         In all other cases, the file will be treated as a raw binary file.
126         In both cases, the file's contents are stored in bytes for subsequent
127         usage to program a device or to perform a crc check.
129         Parameters:
130             path -- A str with the path to the firmware file.
132         Attributes:
133             bytes: A bytearray with firmware contents ready to send to the device
134         """
135         self._crc32 = None
136         firmware_is_hex = False
138         if have_magic:
139             file_type = bytearray(magic.from_file(path, True))
141             #from_file() returns bytes with PY3, str with PY2. This comparison
142             #will be True in both cases"""
143             if file_type == b'text/plain':
144                 firmware_is_hex = True
145                 mdebug(5, "Firmware file: Intel Hex")
146             elif file_type == b'application/octet-stream':
147                 mdebug(5, "Firmware file: Raw Binary")
148             else:
149                 error_str = "Could not determine firmware type. Magic " \
150                             "indicates '%s'" % (file_type)
151                 raise CmdException(error_str)
152         else:
153             if os.path.splitext(path)[1][1:] in self.HEX_FILE_EXTENSIONS:
154                 firmware_is_hex = True
155                 mdebug(5, "Your firmware looks like an Intel Hex file")
156             else:
157                 mdebug(5, "Cannot auto-detect firmware filetype: Assuming .bin")
159             mdebug(10, "For more solid firmware type auto-detection, install "
160                        "python-magic.")
161             mdebug(10, "Please see the readme for more details.")
163         if firmware_is_hex:
164             if have_hex_support:
165                 self.bytes = bytearray(IntelHex(path).tobinarray())
166                 return
167             else:
168                 error_str = "Firmware is Intel Hex, but the IntelHex library " \
169                             "could not be imported.\n" \
170                             "Install IntelHex in site-packages or program " \
171                             "your device with a raw binary (.bin) file.\n" \
172                             "Please see the readme for more details."
173                 raise CmdException(error_str)
175         with open(path, 'rb') as f:
176             self.bytes = bytearray(f.read())
178     def crc32(self):
179         """
180         Return the crc32 checksum of the firmware image
182         Return:
183             The firmware's CRC32, ready for comparison with the CRC
184             returned by the ROM bootloader's COMMAND_CRC32
185         """
186         if self._crc32 is None:
187             self._crc32 = binascii.crc32(bytearray(self.bytes)) & 0xffffffff
189         return self._crc32
191 class CommandInterface(object):
192     ACK_BYTE = 0xCC
193     NACK_BYTE = 0x33
194     def open(self, aport='/dev/tty.usbserial-000013FAB', abaudrate=500000):
195         self.sp = serial.Serial(
196             port=aport,
197             baudrate=abaudrate,     # baudrate
198             bytesize=8,             # number of databits
199             parity=serial.PARITY_NONE,
200             stopbits=1,
201             xonxoff=0,              # enable software flow control
202             rtscts=0,               # disable RTS/CTS flow control
203             timeout=3             # set a timeout value, None for waiting forever
204         )
205         
207     def invoke_bootloader(self, dtr_active_high=False, inverted=False):
208         # Use the DTR and RTS lines to control bootloader and the !RESET pin.
209         # This can automatically invoke the bootloader without the user
210         # having to toggle any pins.
211         #
212         # If inverted is False (default):
213         # DTR: connected to the bootloader pin
214         # RTS: connected to !RESET
215         # If inverted is True, pin connections are the other way round
216         if inverted:
217             set_bootloader_pin = self.sp.setRTS
218             set_reset_pin = self.sp.setDTR
219         else:
220             set_bootloader_pin = self.sp.setDTR
221             set_reset_pin = self.sp.setRTS
222         
223         # BMH: Forze DTR   
224         mdebug(0, "Forze DTR Inactive (Active = %d) RTS-DTR Inverted: %d" % (dtr_active_high,inverted))
225         set_bootloader_pin(1 if dtr_active_high else 0)
226         time.sleep(0.2)
227         
228         set_bootloader_pin(0 if dtr_active_high else 1)
229         set_reset_pin(0)
230         set_reset_pin(1)
231         set_reset_pin(0)
232         time.sleep(0.002)  # Make sure the pin is still asserted when the chip
233                            # comes out of reset. This fixes an issue where there
234                            # wasn't enough delay here on Mac.
235         set_bootloader_pin(0 if not dtr_active_high else 1)
237         #set_reset_pin(0)
238         #set_bootloader_pin(0)
239                 #set_reset_pin(1)
240         #set_bootloader_pin(1)
241         
242         #set_reset_pin(0)
243         #time.sleep(0.002)  # Make sure the pin is still asserted when the chip
244                            # comes out of reset. This fixes an issue where there
245                            # wasn't enough delay here on Mac.
246         #set_bootloader_pin(0 if not dtr_active_high else 1)
251         # Some boards have a co-processor that detects this sequence here and
252         # then drives the main chip's BSL enable and !RESET pins. Depending on
253         # board design and co-processor behaviour, the !RESET pin may get
254         # asserted after we have finished the sequence here. In this case, we
255         # need a small delay so as to avoid trying to talk to main chip before
256         # it has actually entered its bootloader mode.
257         #
258         # See contiki-os/contiki#1533
259         time.sleep(0.1)
261     def close(self):
262         self.sp.close()
265     def _wait_for_ack(self, info = "", timeout = 1):
266         stop = time.time() + timeout
267         got = bytearray(2)
268         while got[-2] != 00 or got[-1] not in (CommandInterface.ACK_BYTE,
269                                                CommandInterface.NACK_BYTE):
270             got += self._read(1)
271             if time.time() > stop:
272                 raise CmdException("Timeout waiting for ACK/NACK after '%s'"
273                                    % (info,))
275         # Our bytearray's length is: 2 initial bytes + 2 bytes for the ACK/NACK
276         # plus a possible N-4 additional (buffered) bytes
277         mdebug(10, "Got %d additional bytes before ACK/NACK" % (len(got) - 4,))
279         # wait for ask
280         ask = got[-1]
282         if ask == CommandInterface.ACK_BYTE:
283             # ACK
284             return 1
285         elif ask == CommandInterface.NACK_BYTE:
286             # NACK
287             mdebug(10, "Target replied with a NACK during %s" % info)
288             return 0
290         # Unknown response
291         mdebug(10, "Unrecognised response 0x%x to %s" % (ask, info))
292         return 0
294     def _encode_addr(self, addr):
295         byte3 = (addr >> 0) & 0xFF
296         byte2 = (addr >> 8) & 0xFF
297         byte1 = (addr >> 16) & 0xFF
298         byte0 = (addr >> 24) & 0xFF
299         if PY3:
300             return bytes([byte0, byte1, byte2, byte3])
301         else:
302             return (chr(byte0) + chr(byte1) + chr(byte2) + chr(byte3))
304     def _decode_addr(self, byte0, byte1, byte2, byte3):
305         return ((byte3 << 24) | (byte2 << 16) | (byte1 << 8) | (byte0 << 0))
307     def _calc_checks(self, cmd, addr, size):
308         return ((sum(bytearray(self._encode_addr(addr)))
309                  +sum(bytearray(self._encode_addr(size)))
310                  +cmd)
311                 &0xFF)
313     def _write(self, data, is_retry=False):
314         if PY3:
315             if type(data) == int:
316                 assert data < 256
317                 goal = 1
318                 written = self.sp.write(bytes([data]))
319             elif type(data) == bytes or type(data) == bytearray:
320                 goal = len(data)
321                 written = self.sp.write(data)
322             else:
323                 raise CmdException("Internal Error. Bad data type: {}".format(type(data)))
324         else:
325             if type(data) == int:
326                 assert data < 256
327                 goal = 1
328                 written = self.sp.write(chr(data))
329             else:
330                 goal = len(data)
331                 written = self.sp.write(data)
332         if written < goal:
333             mdebug(10, "*** Only wrote {} of target {} bytes".format(written, goal))
334             if is_retry and written == 0:
335                 raise CmdException("Failed to write data on the serial bus")
336             mdebug(10, "*** Retrying write for remainder")
337             if type(data) == int:
338                 return self._write(data, is_retry=True)
339             else:
340                 return self._write(data[written:], is_retry=True)
342     def _read(self, length):
343         return bytearray(self.sp.read(length))
345     def sendAck(self):
346         self._write(0x00)
347         self._write(0xCC)
348         return
350     def sendNAck(self):
351         self._write(0x00)
352         self._write(0x33)
353         return
356     def receivePacket(self):
357         # stop = time.time() + 5
358         # got = None
359         # while not got:
360         got = self._read(2)
361         #     if time.time() > stop:
362         #         break
364         # if not got:
365         #     raise CmdException("No response to %s" % info)
367         size = got[0] #rcv size
368         chks = got[1] #rcv checksum
369         data = bytearray(self._read(size - 2)) # rcv data
371         mdebug(10, "*** received %x bytes" % size)
372         if chks == sum(data)&0xFF:
373             self.sendAck()
374             return data
375         else:
376             self.sendNAck()
377             #TODO: retry receiving!
378             raise CmdException("Received packet checksum error")
379             return 0
381     def sendSynch(self):
382         cmd = 0x55
384         self.sp.flushInput() #flush serial input buffer for first ACK reception
386         mdebug(10, "*** sending synch sequence")
387         self._write(cmd) # send U
388         self._write(cmd) # send U
389         return self._wait_for_ack("Synch (0x55 0x55)", 2)
391     def checkLastCmd(self):
392         stat = self.cmdGetStatus()
393         if not (stat):
394             raise CmdException("No response from target on status request. (Did you disable the bootloader?)")
396         if stat[0] == COMMAND_RET_SUCCESS:
397             mdebug(10, "Command Successful")
398             return 1
399         else:
400             stat_str = RETURN_CMD_STRS.get(stat[0], None)
401             if stat_str is None:
402                 mdebug(0, 'Warning: unrecognized status returned 0x%x' % stat[0])
403             else:
404                 mdebug(0, "Target returned: 0x%x, %s" % (stat[0], stat_str))
405             return 0
408     def cmdPing(self):
409         cmd = 0x20
410         lng = 3
412         self._write(lng) # send size
413         self._write(cmd) # send checksum
414         self._write(cmd) # send data
416         mdebug(10, "*** Ping command (0x20)")
417         if self._wait_for_ack("Ping (0x20)"):
418             return self.checkLastCmd()
420     def cmdReset(self):
421         cmd = 0x25
422         lng = 3
424         self._write(lng) # send size
425         self._write(cmd) # send checksum
426         self._write(cmd) # send data
428         mdebug(10, "*** Reset command (0x25)")
429         if self._wait_for_ack("Reset (0x25)"):
430             return 1
432     def cmdGetChipId(self):
433         cmd = 0x28
434         lng = 3
436         self._write(lng) # send size
437         self._write(cmd) # send checksum
438         self._write(cmd) # send data
440         mdebug(10, "*** GetChipId command (0x28)")
441         if self._wait_for_ack("Get ChipID (0x28)"):
442             version = self.receivePacket() # 4 byte answ, the 2 LSB hold chip ID
443             if self.checkLastCmd():
444                 assert len(version) == 4, "Unreasonable chip id: %s" % repr(version)
445                 mdebug(10, "    Version 0x%02X%02X%02X%02X" % tuple(version))
446                 chip_id = (version[2] << 8) | version[3]
447                 return chip_id
448             else:
449                 raise CmdException("GetChipID (0x28) failed")
451     def cmdGetStatus(self):
452         cmd = 0x23
453         lng = 3
455         self._write(lng) # send size
456         self._write(cmd) # send checksum
457         self._write(cmd) # send data
459         mdebug(10, "*** GetStatus command (0x23)")
460         if self._wait_for_ack("Get Status (0x23)"):
461             stat = self.receivePacket()
462             return stat
464     def cmdSetXOsc(self):
465         cmd = 0x29
466         lng = 3
468         self._write(lng) # send size
469         self._write(cmd) # send checksum
470         self._write(cmd) # send data
472         mdebug(10, "*** SetXOsc command (0x29)")
473         if self._wait_for_ack("SetXOsc (0x29)"):
474             return 1
475             # UART speed (needs) to be changed!
477     def cmdRun(self, addr):
478         cmd=0x22
479         lng=7
481         self._write(lng) # send length
482         self._write(self._calc_checks(cmd,addr,0)) # send checksum
483         self._write(cmd) # send cmd
484         self._write(self._encode_addr(addr)) # send addr
486         mdebug(10, "*** Run command(0x22)")
487         return 1
489     def cmdEraseMemory(self, addr, size):
490         cmd=0x26
491         lng=11
493         self._write(lng) # send length
494         self._write(self._calc_checks(cmd,addr,size)) # send checksum
495         self._write(cmd) # send cmd
496         self._write(self._encode_addr(addr)) # send addr
497         self._write(self._encode_addr(size)) # send size
499         mdebug(10, "*** Erase command(0x26)")
500         if self._wait_for_ack("Erase memory (0x26)",10):
501             return self.checkLastCmd()
503     def cmdBankErase(self):
504         cmd = 0x2C
505         lng = 3
507         self._write(lng) # send length
508         self._write(cmd) # send checksum
509         self._write(cmd) # send cmd
511         mdebug(10, "*** Bank Erase command(0x2C)")
512         if self._wait_for_ack("Bank Erase (0x2C)",10):
513             return self.checkLastCmd()
515     def cmdCRC32(self, addr, size):
516         cmd=0x27
517         lng=11
519         self._write(lng) # send length
520         self._write(self._calc_checks(cmd,addr,size)) # send checksum
521         self._write(cmd) # send cmd
522         self._write(self._encode_addr(addr)) # send addr
523         self._write(self._encode_addr(size)) # send size
525         mdebug(10, "*** CRC32 command(0x27)")
526         if self._wait_for_ack("Get CRC32 (0x27)",1):
527             crc=self.receivePacket()
528             if self.checkLastCmd():
529                 return self._decode_addr(crc[3],crc[2],crc[1],crc[0])
531     def cmdCRC32CC26xx(self, addr, size):
532         cmd = 0x27
533         lng = 15
535         self._write(lng) # send length
536         self._write(self._calc_checks(cmd, addr, size)) # send checksum
537         self._write(cmd) # send cmd
538         self._write(self._encode_addr(addr)) # send addr
539         self._write(self._encode_addr(size)) # send size
540         self._write(self._encode_addr(0x00000000)) # send number of reads
542         mdebug(10, "*** CRC32 command(0x27)")
543         if self._wait_for_ack("Get CRC32 (0x27)", 1):
544             crc=self.receivePacket()
545             if self.checkLastCmd():
546                 return self._decode_addr(crc[3], crc[2], crc[1], crc[0])
548     def cmdDownload(self, addr, size):
549         cmd=0x21
550         lng=11
552         if (size % 4) != 0: # check for invalid data lengths
553             raise Exception('Invalid data size: %i. Size must be a multiple of 4.' % size)
555         self._write(lng) # send length
556         self._write(self._calc_checks(cmd,addr,size)) # send checksum
557         self._write(cmd) # send cmd
558         self._write(self._encode_addr(addr)) # send addr
559         self._write(self._encode_addr(size)) # send size
561         mdebug(10, "*** Download command (0x21)")
562         if self._wait_for_ack("Download (0x21)",2):
563             return self.checkLastCmd()
565     def cmdSendData(self, data):
566         cmd=0x24
567         lng=len(data)+3
568         # TODO: check total size of data!! max 252 bytes!
570         self._write(lng) # send size
571         self._write((sum(bytearray(data))+cmd)&0xFF) # send checksum
572         self._write(cmd) # send cmd
573         self._write(bytearray(data)) # send data
575         mdebug(10, "*** Send Data (0x24)")
576         if self._wait_for_ack("Send data (0x24)",10):
577             return self.checkLastCmd()
579     def cmdMemRead(self, addr): # untested
580         cmd=0x2A
581         lng=8
583         self._write(lng) # send length
584         self._write(self._calc_checks(cmd,addr,4)) # send checksum
585         self._write(cmd) # send cmd
586         self._write(self._encode_addr(addr)) # send addr
587         self._write(4) # send width, 4 bytes
589         mdebug(10, "*** Mem Read (0x2A)")
590         if self._wait_for_ack("Mem Read (0x2A)",1):
591             data = self.receivePacket()
592             if self.checkLastCmd():
593                 return data # self._decode_addr(ord(data[3]),ord(data[2]),ord(data[1]),ord(data[0]))
595     def cmdMemReadCC26xx(self, addr):
596         cmd = 0x2A
597         lng = 9
599         self._write(lng) # send length
600         self._write(self._calc_checks(cmd, addr, 2)) # send checksum
601         self._write(cmd) # send cmd
602         self._write(self._encode_addr(addr)) # send addr
603         self._write(1) # send width, 4 bytes
604         self._write(1) # send number of reads
606         mdebug(10, "*** Mem Read (0x2A)")
607         if self._wait_for_ack("Mem Read (0x2A)", 1):
608             data = self.receivePacket()
609             if self.checkLastCmd():
610                 return data
612     def cmdMemWrite(self, addr, data, width): # untested
613         # TODO: check width for 1 or 4 and data size
614         cmd=0x2B
615         lng=10
617         self._write(lng) # send length
618         self._write(self._calc_checks(cmd,addr,0)) # send checksum
619         self._write(cmd) # send cmd
620         self._write(self._encode_addr(addr)) # send addr
621         self._write(bytearray(data)) # send data
622         self._write(width) # send width, 4 bytes
624         mdebug(10, "*** Mem write (0x2B)")
625         if self._wait_for_ack("Mem Write (0x2B)",2):
626             return checkLastCmd()
629 # Complex commands section
631     def writeMemory(self, addr, data):
632         lng = len(data)
633         trsf_size = 248 # amount of data bytes transferred per packet (theory: max 252 + 3)
634         empty_packet = bytearray((0xFF,) * trsf_size)
636         # Boot loader enable check
637         # TODO: implement check for all chip sizes & take into account partial firmware uploads
638         if (lng == 524288): #check if file is for 512K model
639             if not ((data[524247] & (1 << 4)) >> 4): #check the boot loader enable bit  (only for 512K model)
640                 if not ( conf['force'] or query_yes_no("The boot loader backdoor is not enabled "\
641                     "in the firmware you are about to write to the target. "\
642                     "You will NOT be able to reprogram the target using this tool if you continue! "\
643                     "Do you want to continue?","no") ):
644                     raise Exception('Aborted by user.')
646         mdebug(5, "Writing %(lng)d bytes starting at address 0x%(addr)08X" %
647                { 'lng': lng, 'addr': addr})
649         offs = 0
650         addr_set = 0
652         while lng > trsf_size: #check if amount of remaining data is less then packet size
653             if data[offs:offs+trsf_size] != empty_packet: #skip packets filled with 0xFF
654                 if addr_set != 1:
655                     self.cmdDownload(addr,lng) #set starting address if not set
656                     addr_set = 1
657                 mdebug(5, " Write %(len)d bytes at 0x%(addr)08X" % {'addr': addr, 'len': trsf_size}, '\r')
658                 sys.stdout.flush()
660                 self.cmdSendData(data[offs:offs+trsf_size]) # send next data packet
661             else:   # skipped packet, address needs to be set
662                 addr_set = 0
664             offs = offs + trsf_size
665             addr = addr + trsf_size
666             lng = lng - trsf_size
668         mdebug(5, "Write %(len)d bytes at 0x%(addr)08X" % {'addr': addr, 'len': lng})
669         self.cmdDownload(addr,lng)
670         return self.cmdSendData(data[offs:offs+lng]) # send last data packet
672 class Chip(object):
673     def __init__(self, command_interface):
674         self.command_interface = command_interface
676         # Some defaults. The child can override.
677         self.flash_start_addr = 0x00000000
678         self.has_cmd_set_xosc = False
680     def crc(self, address, size):
681         return getattr(self.command_interface, self.crc_cmd)(address, size)
683     def disable_bootloader(self):
684         if not (conf['force'] or query_yes_no("Disabling the bootloader will prevent you from "\
685                             "using this script until you re-enable the bootloader "\
686                             "using JTAG. Do you want to continue?", "no")):
687             raise Exception('Aborted by user.')
689         if PY3:
690             pattern = struct.pack('<L', self.bootloader_dis_val)
691         else:
692             pattern = [ord(b) for b in struct.pack('<L', self.bootloader_dis_val)]
694         if cmd.writeMemory(self.bootloader_address, pattern):
695             mdebug(5, "    Set bootloader closed done                      ")
696         else:
697             raise CmdException("Set bootloader closed failed             ")
699 class CC2538(Chip):
700     def __init__(self, command_interface):
701         super(CC2538, self).__init__(command_interface)
702         self.flash_start_addr = 0x00200000
703         self.addr_ieee_address_secondary = 0x0027ffcc
704         self.has_cmd_set_xosc = True
705         self.bootloader_dis_val = 0xefffffff
706         self.crc_cmd = "cmdCRC32"
708         FLASH_CTRL_DIECFG0 = 0x400D3014
709         FLASH_CTRL_DIECFG2 = 0x400D301C
710         addr_ieee_address_primary = 0x00280028
711         ccfg_len = 44
713         #Read out primary IEEE address, flash and RAM size
714         model = self.command_interface.cmdMemRead(FLASH_CTRL_DIECFG0)
715         self.size = (model[3] & 0x70) >> 4
716         if 0 < self.size <= 4:
717             self.size *= 0x20000 # in bytes
718         else:
719             self.size = 0x10000 # in bytes
720         self.bootloader_address = self.flash_start_addr + self.size - ccfg_len
722         sram = (((model[2] << 8) | model[3]) & 0x380) >> 7
723         sram = (2 - sram) << 3 if sram <= 1 else 32 # in KB
725         pg = self.command_interface.cmdMemRead(FLASH_CTRL_DIECFG2)
726         pg_major = (pg[2] & 0xF0) >> 4
727         if pg_major == 0:
728             pg_major = 1
729         pg_minor = pg[2] & 0x0F
731         ti_oui = bytearray([0x00, 0x12, 0x4B])
732         ieee_addr = self.command_interface.cmdMemRead(addr_ieee_address_primary)
733         ieee_addr_end = self.command_interface.cmdMemRead(addr_ieee_address_primary + 4)
734         if ieee_addr[:3] == ti_oui:
735             ieee_addr += ieee_addr_end
736         else:
737             ieee_addr = ieee_addr_end + ieee_addr
739         mdebug(5, "CC2538 PG%d.%d: %dKB Flash, %dKB SRAM, CCFG at 0x%08X"
740                % (pg_major, pg_minor, self.size >> 10, sram,
741                   self.bootloader_address))
742         mdebug(5, "Primary IEEE Address: %s" % (':'.join('%02X' % x for x in ieee_addr)))
744     def erase(self):
745         mdebug(5, "Erasing %s bytes starting at address 0x%08X" % (self.size, self.flash_start_addr))
746         return self.command_interface.cmdEraseMemory(self.flash_start_addr, self.size)
748     def read_memory(self, addr):
749         # CC2538's COMMAND_MEMORY_READ sends each 4-byte number in inverted
750         # byte order compared to what's written on the device
751         data = self.command_interface.cmdMemRead(addr)
752         return bytearray([data[x] for x in range(3, -1, -1)])
754 class CC26xx(Chip):
755     # Class constants
756     MISC_CONF_1 = 0x500010A0
757     PROTO_MASK_BLE = 0x01
758     PROTO_MASK_IEEE = 0x04
759     PROTO_MASK_BOTH = 0x05
761     def __init__(self, command_interface):
762         super(CC26xx, self).__init__(command_interface)
763         self.bootloader_dis_val = 0x00000000
764         self.crc_cmd = "cmdCRC32CC26xx"
766         ICEPICK_DEVICE_ID = 0x50001318
767         FCFG_USER_ID = 0x50001294
768         PRCM_RAMHWOPT = 0x40082250
769         FLASH_SIZE = 0x4003002C
770         addr_ieee_address_primary = 0x500012F0
771         ccfg_len = 88
772         ieee_address_secondary_offset = 0x20
773         bootloader_dis_offset = 0x30
774         sram = "Unknown"
776         # Determine CC13xx vs CC26xx via ICEPICK_DEVICE_ID::WAFER_ID and store
777         # PG revision
778         device_id = self.command_interface.cmdMemReadCC26xx(ICEPICK_DEVICE_ID)
779         wafer_id = (((device_id[3] & 0x0F) << 16) +
780                     (device_id[2] << 8) +
781                     (device_id[1] & 0xF0)) >> 4
782         pg_rev = (device_id[3] & 0xF0) >> 4
784         # Read FCFG1_USER_ID to get the package and supported protocols
785         user_id = self.command_interface.cmdMemReadCC26xx(FCFG_USER_ID)
786         package = {0x00: '4x4mm', 0x01: '5x5mm', 0x02: '7x7mm'}.get(user_id[2] & 0x03, "Unknown")
787         protocols = user_id[1] >> 4
789         # We can now detect the exact device
790         if wafer_id == 0xB99A:
791             chip = self._identify_cc26xx(pg_rev, protocols)
792         elif wafer_id == 0xB9BE:
793             chip = self._identify_cc13xx(pg_rev, protocols)
795         # Read flash size, calculate and store bootloader disable address
796         self.size = self.command_interface.cmdMemReadCC26xx(FLASH_SIZE)[0] * 4096
797         self.bootloader_address = self.size - ccfg_len + bootloader_dis_offset
798         self.addr_ieee_address_secondary = self.size - ccfg_len + ieee_address_secondary_offset
800         # RAM size
801         ramhwopt_size = self.command_interface.cmdMemReadCC26xx(PRCM_RAMHWOPT)[0] & 3
802         if ramhwopt_size == 3:
803             sram = "20KB"
804         elif ramhwopt_size == 2:
805             sram = "16KB"
806         else:
807             sram = "Unknown"
809         # Primary IEEE address. Stored with the MSB at the high address
810         ieee_addr = self.command_interface.cmdMemReadCC26xx(addr_ieee_address_primary + 4)[::-1]
811         ieee_addr += self.command_interface.cmdMemReadCC26xx(addr_ieee_address_primary)[::-1]
813         mdebug(5, "%s (%s): %dKB Flash, %s SRAM, CCFG.BL_CONFIG at 0x%08X"
814                % (chip, package, self.size >> 10, sram,
815                   self.bootloader_address))
816         mdebug(5, "Primary IEEE Address: %s" % (':'.join('%02X' % x for x in ieee_addr)))
818     def _identify_cc26xx(self, pg, protocols):
819         chips_dict = {
820             CC26xx.PROTO_MASK_IEEE: 'CC2630',
821             CC26xx.PROTO_MASK_BLE: 'CC2640',
822             CC26xx.PROTO_MASK_BOTH: 'CC2650',
823         }
825         chip_str = chips_dict.get(protocols & CC26xx.PROTO_MASK_BOTH, "Unknown")
827         if pg == 1:
828             pg_str = "PG1.0"
829         elif pg == 3:
830             pg_str = "PG2.0"
831         elif pg == 7:
832             pg_str = "PG2.1"
833         elif pg == 8:
834             rev_minor = self.command_interface.cmdMemReadCC26xx(CC26xx.MISC_CONF_1)[0]
835             if rev_minor == 0xFF:
836                 rev_minor = 0x00
837             pg_str = "PG2.%d" % (2 + rev_minor,)
839         return "%s %s" % (chip_str, pg_str)
841     def _identify_cc13xx(self, pg, protocols):
842         chip_str = "CC1310"
843         if protocols & CC26xx.PROTO_MASK_IEEE == CC26xx.PROTO_MASK_IEEE:
844             chip_str = "CC1350"
846         if pg == 0:
847             pg_str = "PG1.0"
848         elif pg == 2:
849             rev_minor = self.command_interface.cmdMemReadCC26xx(CC26xx.MISC_CONF_1)[0]
850             if rev_minor == 0xFF:
851                 rev_minor = 0x00
852             pg_str = "PG2.%d" % (rev_minor,)
854         return "%s %s" % (chip_str, pg_str)
856     def erase(self):
857         mdebug(5, "Erasing all main bank flash sectors")
858         return self.command_interface.cmdBankErase()
860     def read_memory(self, addr):
861         # CC26xx COMMAND_MEMORY_READ returns contents in the same order as
862         # they are stored on the device
863         return self.command_interface.cmdMemReadCC26xx(addr)
865 def query_yes_no(question, default="yes"):
866     valid = {"yes":True,   "y":True,  "ye":True,
867              "no":False,     "n":False}
868     if default == None:
869         prompt = " [y/n] "
870     elif default == "yes":
871         prompt = " [Y/n] "
872     elif default == "no":
873         prompt = " [y/N] "
874     else:
875         raise ValueError("invalid default answer: '%s'" % default)
877     while True:
878         sys.stdout.write(question + prompt)
879         if PY3:
880             choice = input().lower()
881         else:
882             choice = raw_input().lower()
883         if default is not None and choice == '':
884             return valid[default]
885         elif choice in valid:
886             return valid[choice]
887         else:
888             sys.stdout.write("Please respond with 'yes' or 'no' "\
889                              "(or 'y' or 'n').\n")
891 # Convert the entered IEEE address into an integer
892 def parse_ieee_address (inaddr):
893     try:
894         return int(inaddr, 16)
895     except ValueError:
896         # inaddr is not a hex string, look for other formats
897         if ':' in inaddr:
898             bytes = inaddr.split(':')
899         elif '-' in inaddr:
900             bytes = inaddr.split('-')
901         if len(bytes) != 8:
902             raise ValueError("Supplied IEEE address does not contain 8 bytes")
903         addr = 0
904         for i,b in zip(range(8), bytes):
905             try:
906                 addr += int(b, 16) << (56-(i*8))
907             except ValueError:
908                 raise ValueError("IEEE address contains invalid bytes")
909         return addr
911 def print_version():
912     # Get the version using "git describe".
913     try:
914         p = Popen(['git', 'describe', '--tags', '--match', '[0-9]*'],
915                   stdout=PIPE, stderr=PIPE)
916         p.stderr.close()
917         line = p.stdout.readlines()[0]
918         version = line.strip()
919     except:
920     # We're not in a git repo, or git failed, use fixed version string.
921         version = VERSION_STRING
922     print('%s %s' % (sys.argv[0], version))
924 def usage():
925     print("""Usage: %s [-DhqVfewvr] [-l length] [-p port] [-b baud] [-a addr] [-i addr] [--bootloader-active-high] [--bootloader-invert-lines] [file.bin]
926     -h, --help               This help
927     -q                       Quiet
928     -V                       Verbose
929     -f                       Force operation(s) without asking any questions
930     -e                       Erase (full)
931     -w                       Write
932     -v                       Verify (CRC32 check)
933     -r                       Read
934     -l length                Length of read
935     -p port                  Serial port (default: first USB-like port in /dev)
936     -b baud                  Baud speed (default: 500000)
937     -a addr                  Target address
938     -i, --ieee-address addr  Set the secondary 64 bit IEEE address
939     --bootloader-active-high Use active high signals to enter bootloader
940     --bootloader-invert-lines Inverts the use of RTS and DTR to enter bootloader
941     -D, --disable-bootloader After finishing, disable the bootloader
942     --version                Print script version
944 Examples:
945     ./%s -e -w -v example/main.bin
946     ./%s -e -w -v --ieee-address 00:12:4b:aa:bb:cc:dd:ee example/main.bin
948     """ % (sys.argv[0],sys.argv[0],sys.argv[0]))
950 if __name__ == "__main__":
952     conf = {
953             'port': 'auto',
954             'baud': 500000,
955             'force_speed' : 0,
956             'address': None,
957             'force': 0,
958             'erase': 0,
959             'write': 0,
960             'verify': 0,
961             'read': 0,
962             'len': 0x80000,
963             'fname':'',
964             'ieee_address': 0,
965             'bootloader_active_high': False,
966             'bootloader_invert_lines' : False,
967             'disable-bootloader': 0
968         }
970 # http://www.python.org/doc/2.5.2/lib/module-getopt.html
972     try:
973         opts, args = getopt.getopt(sys.argv[1:], "DhqVfewvrp:b:a:l:i:", ['help', 'ieee-address=', 'disable-bootloader', 'bootloader-active-high', 'bootloader-invert-lines', 'version'])
974     except getopt.GetoptError as err:
975         # print help information and exit:
976         print(str(err)) # will print something like "option -a not recognized"
977         usage()
978         sys.exit(2)
980     for o, a in opts:
981         if o == '-V':
982             QUIET = 10
983         elif o == '-q':
984             QUIET = 0
985         elif o == '-h' or o == '--help':
986             usage()
987             sys.exit(0)
988         elif o == '-f':
989             conf['force'] = 1
990         elif o == '-e':
991             conf['erase'] = 1
992         elif o == '-w':
993             conf['write'] = 1
994         elif o == '-v':
995             conf['verify'] = 1
996         elif o == '-r':
997             conf['read'] = 1
998         elif o == '-p':
999             conf['port'] = a
1000         elif o == '-b':
1001             conf['baud'] = eval(a)
1002             conf['force_speed'] = 1
1003         elif o == '-a':
1004             conf['address'] = eval(a)
1005         elif o == '-l':
1006             conf['len'] = eval(a)
1007         elif o == '-i' or o == '--ieee-address':
1008             conf['ieee_address'] = str(a)
1009         elif o == '--bootloader-active-high':
1010             conf['bootloader_active_high'] = True
1011         elif o == '--bootloader-invert-lines':
1012             conf['bootloader_invert_lines'] = True
1013         elif o == '-D' or o == '--disable-bootloader':
1014             conf['disable-bootloader'] = 1
1015         elif o == '--version':
1016             print_version()
1017             sys.exit(0)
1018         else:
1019             assert False, "Unhandled option"
1021     try:
1022         # Sanity checks
1023         if conf['write'] or conf['read'] or conf['verify']:    # check for input/output file
1024             try:
1025                 args[0]
1026             except:
1027                 raise Exception('No file path given.')
1029         if conf['write'] and conf['read']:
1030             if not ( conf['force'] or query_yes_no("You are reading and writing to the same file. This will overwrite your input file. "\
1031             "Do you want to continue?","no") ):
1032                 raise Exception('Aborted by user.')
1033         if conf['erase'] and conf['read'] and not conf['write']:
1034             if not ( conf['force'] or query_yes_no("You are about to erase your target before reading. "\
1035             "Do you want to continue?","no") ):
1036                 raise Exception('Aborted by user.')
1038         if conf['read'] and not conf['write'] and conf['verify']:
1039             raise Exception('Verify after read not implemented.')
1041         if conf['len'] < 0:
1042             raise Exception('Length must be positive but %d was provided'
1043                             % (conf['len'],))
1045         # Try and find the port automatically
1046         if conf['port'] == 'auto':
1047             ports = []
1049             # Get a list of all USB-like names in /dev
1050             for name in ['tty.usbserial', 'ttyUSB', 'tty.usbmodem', 'tty.SLAB_USBtoUART']:
1051                 ports.extend(glob.glob('/dev/%s*' % name))
1053             ports = sorted(ports)
1055             if ports:
1056                 # Found something - take it
1057                 conf['port'] = ports[0]
1058             else:
1059                 raise Exception('No serial port found.')
1061         cmd = CommandInterface()
1062         cmd.open(conf['port'], conf['baud'])
1063         cmd.invoke_bootloader(conf['bootloader_active_high'], conf['bootloader_invert_lines'])
1064         mdebug(5, "Opening port %(port)s, baud %(baud)d" % {'port':conf['port'],
1065                                                       'baud':conf['baud']})
1066         if conf['write'] or conf['verify']:
1067             mdebug(5, "Reading data from %s" % args[0])
1068             firmware = FirmwareFile(args[0])
1070         mdebug(5, "Connecting to target...")
1072         if not cmd.sendSynch():
1073             raise CmdException("Can't connect to target. Ensure boot loader is started. (no answer on synch sequence)")
1075         # if (cmd.cmdPing() != 1):
1076         #     raise CmdException("Can't connect to target. Ensure boot loader is started. (no answer on ping command)")
1078         chip_id = cmd.cmdGetChipId()
1079         chip_id_str = CHIP_ID_STRS.get(chip_id, None)
1081         if chip_id_str is None:
1082             mdebug(10, '    Unrecognized chip ID. Trying CC13xx/CC26xx')
1083             device = CC26xx(cmd)
1084         else:
1085             mdebug(10, "    Target id 0x%x, %s" % (chip_id, chip_id_str))
1086             device = CC2538(cmd)
1088         # Choose a good default address unless the user specified -a
1089         if conf['address'] is None:
1090             conf['address'] = device.flash_start_addr
1092         if conf['force_speed'] != 1 and device.has_cmd_set_xosc:
1093             if cmd.cmdSetXOsc(): #switch to external clock source
1094                 cmd.close()
1095                 conf['baud'] = 1000000
1096                 cmd.open(conf['port'], conf['baud'])
1097                 mdebug(6, "Opening port %(port)s, baud %(baud)d" % {'port':conf['port'], 'baud':conf['baud']})
1098                 mdebug(6, "Reconnecting to target at higher speed...")
1099                 if (cmd.sendSynch() != 1):
1100                     raise CmdException("Can't connect to target after clock source switch. (Check external crystal)")
1101             else:
1102                 raise CmdException("Can't switch target to external clock source. (Try forcing speed)")
1104         if conf['erase']:
1105             # we only do full erase for now
1106             if device.erase():
1107                 mdebug(5, "    Erase done")
1108             else:
1109                 raise CmdException("Erase failed")
1111         if conf['write']:
1112             # TODO: check if boot loader back-door is open, need to read flash size first to get address
1113             if cmd.writeMemory(conf['address'], firmware.bytes):
1114                 mdebug(5, "    Write done                                ")
1115             else:
1116                 raise CmdException("Write failed                       ")
1118         if conf['verify']:
1119             mdebug(5,"Verifying by comparing CRC32 calculations.")
1121             crc_local = firmware.crc32()
1122             crc_target = device.crc(conf['address'], len(firmware.bytes)) #CRC of target will change according to length input file
1124             if crc_local == crc_target:
1125                 mdebug(5, "    Verified (match: 0x%08x)" % crc_local)
1126             else:
1127                 cmd.cmdReset()
1128                 raise Exception("NO CRC32 match: Local = 0x%x, Target = 0x%x" % (crc_local,crc_target))
1130         if conf['ieee_address'] != 0:
1131             ieee_addr = parse_ieee_address(conf['ieee_address'])
1132             if PY3:
1133                 mdebug(5, "Setting IEEE address to %s" % (':'.join(['%02x' % b for b in struct.pack('>Q', ieee_addr)])))
1134                 ieee_addr_bytes = struct.pack('<Q', ieee_addr)
1135             else:
1136                 mdebug(5, "Setting IEEE address to %s" % (':'.join(['%02x' % ord(b) for b in struct.pack('>Q', ieee_addr)])))
1137                 ieee_addr_bytes = [ord(b) for b in struct.pack('<Q', ieee_addr)]
1139             if cmd.writeMemory(device.addr_ieee_address_secondary, ieee_addr_bytes):
1140                 mdebug(5, "    Set address done                                ")
1141             else:
1142                 raise CmdException("Set address failed                       ")
1144         if conf['read']:
1145             length = conf['len']
1147             # Round up to a 4-byte boundary
1148             length = (length + 3) & ~0x03
1150             mdebug(5, "Reading %s bytes starting at address 0x%x" % (length, conf['address']))
1151             with open(args[0], 'wb') as f:
1152                 for i in range(0, length >> 2):
1153                     rdata = device.read_memory(conf['address'] + (i * 4)) #reading 4 bytes at a time
1154                     mdebug(5, " 0x%x: 0x%02x%02x%02x%02x" % (conf['address'] + (i * 4), rdata[0], rdata[1], rdata[2], rdata[3]), '\r')
1155                     f.write(rdata)
1156                 f.close()
1157             mdebug(5, "    Read done                                ")
1159         if conf['disable-bootloader']:
1160             device.disable_bootloader()
1162         cmd.cmdReset()
1164     except Exception as err:
1165         if QUIET >= 10:
1166             traceback.print_exc()
1167         exit('ERROR: %s' % str(err))