summaryrefslogtreecommitdiffstatshomepage
path: root/cc3200/tools/update-wipy.py
blob: 2d5fe57c2f2ca172ff4009996194c7e4d85ad294 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#!/usr/bin/env python

"""
The WiPy firmware update script. Transmits the specified firmware file
over FTP, and then resets the WiPy and optionally verifies that software
was correctly updated.

Usage:

    ./update-wipy.py --file "path_to_mcuimg.bin" --verify

Or:

    python update-wipy.py --file "path_to_mcuimg.bin"
"""

import sys
import argparse
import time
import socket
from ftplib import FTP
from telnetlib import Telnet


def print_exception(e):
    print ('Exception: {}, on line {}'.format(e, sys.exc_info()[-1].tb_lineno))


def ftp_directory_exists(ftpobj, directory_name):
    filelist = []
    ftpobj.retrlines('LIST',filelist.append)
    for f in filelist:
        if f.split()[-1] == directory_name:
            return True
    return False


def transfer_file(args):
    with FTP(args.ip, timeout=20) as ftp:
        print ('FTP connection established')

        if '230' in ftp.login(args.user, args.password):
            print ('Login successful')

            if '250' in ftp.cwd('/flash'):
                if not ftp_directory_exists(ftp, 'sys'):
                    print ('/flash/sys directory does not exist')
                    if not '550' in ftp.mkd('sys'):
                        print ('/flash/sys directory created')
                    else:
                        print ('Error: cannot create /flash/sys directory')
                        return False
                if '250' in ftp.cwd('sys'):
                    print ("Entered '/flash/sys' directory")
                    with open(args.file, "rb") as fwfile:
                        print ('Firmware image found, initiating transfer...')
                        if '226' in ftp.storbinary("STOR " + 'mcuimg.bin', fwfile, 512):
                            print ('File transfer complete')
                            return True
                        else:
                            print ('Error: file transfer failed')
                else:
                    print ('Error: cannot enter /flash/sys directory')
            else:
                print ('Error: cannot enter /flash directory')
        else:
            print ('Error: ftp login failed')

    return False


def reset_board(args):
    success = False

    try:
        tn = Telnet(args.ip, timeout=5)
        print("Connected via Telnet, trying to login now")

        if b'Login as:' in tn.read_until(b"Login as:", timeout=5):
            tn.write(bytes(args.user, 'ascii') + b"\r\n")

            if b'Password:' in tn.read_until(b"Password:", timeout=5):
                # needed because of internal implementation details of the WiPy's telnet server
                time.sleep(0.2)
                tn.write(bytes(args.password, 'ascii') + b"\r\n")

                if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
                    print("Telnet login succeeded")
                    tn.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
                    time.sleep(1)
                    tn.write(b'\r\x02') # ctrl-B: enter friendly REPL
                    if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
                        tn.write(b"import machine\r\n")
                        tn.write(b"machine.reset()\r\n")
                        time.sleep(2)
                        print("Reset performed")
                        success = True
                    else:
                        print("Error: cannot enter friendly REPL")
                else:
                    print("Error: telnet login failed")

    except Exception as e:
        print_exception(e)
    finally:
        try:
            tn.close()
        except Exception as e:
            pass
        return success


def verify_update(args):
    success = False
    firmware_tag = ''

    def find_tag (tag):
        if tag in firmware_tag:
            print("Verification passed")
            return True
        else:
            print("Error: verification failed, the git tag doesn't match")
            return False

    retries = 0
    while True:
        try:
            # Specify a longer time out value here because the board has just been
            # reset and the wireless connection might not be fully established yet
            tn = Telnet(args.ip, timeout=10)
            print("Connected via telnet again, lets check the git tag")
            break
        except socket.timeout:
            if retries < 5:
                print("Timeout while connecting via telnet, retrying...")
                retries += 1
            else:
                print('Error: Telnet connection timed out!')
                return False

    try:
        firmware_tag = tn.read_until (b'with CC3200')
        tag_file_path = args.file.rstrip('mcuimg.bin') + 'genhdr/mpversion.h'
        
        if args.tag is not None:
            success = find_tag(bytes(args.tag, 'ascii'))
        else:
            with open(tag_file_path) as tag_file:
                for line in tag_file:
                    bline = bytes(line, 'ascii')
                    if b'MICROPY_GIT_HASH' in bline:
                        bline = bline.lstrip(b'#define MICROPY_GIT_HASH ').replace(b'"', b'').replace(b'\r', b'').replace(b'\n', b'')
                        success = find_tag(bline)
                        break

    except Exception as e:
        print_exception(e)
    finally:
        try:
            tn.close()
        except Exception as e:
            pass
        return success


def main():
    cmd_parser = argparse.ArgumentParser(description='Update the WiPy firmware with the specified image file')
    cmd_parser.add_argument('-f', '--file', default=None, help='the path of the firmware file')
    cmd_parser.add_argument('-u', '--user', default='micro', help='the username')
    cmd_parser.add_argument('-p', '--password', default='python', help='the login password')
    cmd_parser.add_argument('--ip', default='192.168.1.1', help='the ip address of the WiPy')
    cmd_parser.add_argument('--verify', action='store_true', help='verify that the update succeeded')
    cmd_parser.add_argument('-t', '--tag', default=None, help='git tag of the firmware image')
    args = cmd_parser.parse_args()

    result = 1

    try:
        if args.file is None:
            raise ValueError('the image file path must be specified')
        if transfer_file(args):
            if reset_board(args):
                if args.verify:
                    print ('Waiting for the WiFi connection to come up again...')
                    # this time is to allow the system's wireless network card to
                    # connect to the WiPy again.
                    time.sleep(5)
                    if verify_update(args):
                        result = 0
                else:
                    result = 0

    except Exception as e:
        print_exception(e)
    finally:
        sys.exit(result)


if __name__ == "__main__":
    main()