dhylands / rshell

Remote Shell for MicroPython
MIT License
953 stars 134 forks source link

Unable to perform file transfert from pyboard #132

Open EricApik opened 4 years ago

EricApik commented 4 years ago

rshell 0.0.28 Windows 10 , driver : microsoft usbser.sys Board : Pytrack (lopy4) , Pycom MicroPython 1.18.2.r7 Each time i try to get file from lopy i'm facing an error (exception) I can do repl, list my file with size (ls -l) but i was unable to do file transfert, each time i got, i have already try to run rshell with '-a' but without more succes Have you any idea how i can solve this issue ?

File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 1102, in recv_file_from_remote dst_file.write(binascii.unhexlify(write_buf[0:read_size])) binascii.Error: Non-hexadecimal digit found

Complete debug trace :

C:\Travail\temp>rshell -p com3 -d cp /flash/L76GNSS.py L76GNSS.y
Debug = True
Port = com3
Baud = 115200
User = micro
Password = python
Wait = 0
List = 0
nocolor = 0
ascii = 0
Timing = 0
Quiet = 0
BUFFER_SIZE = 512
Cmd = [cp, /flash/L76GNSS.py, L76GNSS.y]
Using buffer-size of 32
Connecting to com3 (buffer-size 32)...
Trying to connect to REPL  connected
Testing if ubinascii.unhexlify exists ... ----- About to send 304 bytes of code to the pyboard -----
def test_unhexlify():
    """Checks the micropython firmware to see if ubinascii.unhexlify exists."""
    import ubinascii
    try:
        _ = ubinascii.unhexlify
        return True
    except:
        return False
output = test_unhexlify()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'True\r\n'
-----
Y
Retrieving root directories ... ----- About to send 222 bytes of code to the pyboard -----
def listdir(dirname):
    """Returns a list of filenames contained in the named directory."""
    import os
    return os.listdir(dirname)
output = listdir('/')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"['flash']\r\n"
-----
/flash/
Setting time ... ----- About to send 1695 bytes of code to the pyboard -----
def set_time(rtc_time):
    rtc = None
    try:
        # Pyboard (pyboard doesn't have machine.RTC()).
        # The pyb.RTC.datetime function takes the arguments in the order:
        # (year, month, day, weekday, hour, minute, second, subseconds)
        # http://docs.micropython.org/en/latest/library/pyb.RTC.html#pyb.RTC.datetime
        import pyb
        rtc = pyb.RTC()
        rtc.datetime(rtc_time)
    except:
        try:
            import pycom
            # PyCom's machine.RTC takes its arguments in a slightly different order
            # than the official machine.RTC.
            # (year, month, day, hour, minute, second[, microsecond[, tzinfo]])
            # https://docs.pycom.io/firmwareapi/pycom/machine/rtc/#rtc-init-datetime-none-source-rtc-internal-rc
            rtc_time2 = (rtc_time[0], rtc_time[1], rtc_time[2], rtc_time[4], rtc_time[5], rtc_time[6])
            import machine
            rtc = machine.RTC()
            rtc.init(rtc_time2)
        except:
            try:
                # The machine.RTC documentation was incorrect and doesn't agree with the code, so no link
                # is presented here. The order of the arguments is the same as the pyboard.
                import machine
                rtc = machine.RTC()
                try:
                    # ESP8266 uses rtc.datetime() rather than rtc.init()
                    rtc.datetime(rtc_time)
                except:
                    # ESP32 (at least Loboris port) uses rtc.init()
                    rtc.init(rtc_time)
            except:
                pass
output = set_time((2020, 5, 20, 3, 12, 21, 45, 0))
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'None\r\n'
-----
May 20, 2020 12:21:45
Evaluating board_name ... ----- About to send 710 bytes of code to the pyboard -----
def board_name(default):
    """Returns the boards name (if available)."""
    try:
        import board
        try:
            name = board.name
        except AttributeError:
            # There was a board.py file, but it didn't have an name attribute
            # We also ignore this as an error
            name = default
    except ImportError:
        # No board.py file on the pyboard - not an error
        name = default
    except BaseException as err:
        print('Error encountered executing board.py')
        import sys
        sys.print_exception(err)
        name = default
    return repr(name)
output = board_name('pyboard')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"'pyboard'\r\n"
-----
pyboard
Retrieving time epoch ... ----- About to send 334 bytes of code to the pyboard -----
def get_time_epoch():
    """Determines the epoch used by the MicroPython board."""
    import time
    try:
      return time.gmtime(0)
    except:
      """Assume its a pyboard, with an epoch of 2000."""
      return (2000, 1, 1, 0, 0, 0, 0, 0)
output = get_time_epoch()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'(1970, 1, 1, 0, 0, 0, 3, 1)\r\n'
-----
Jan 01, 1970
Executing "cp /flash/L76GNSS.py L76GNSS.y"
----- About to send 474 bytes of code to the pyboard -----
def get_mode(filename):
    """Returns the mode of a file, which can be used to determine if a file
       exists, if a file is a file or a directory.
    """
    import os
    try:
        # Since this function runs remotely, it can't depend on other functions,
        # so we can't call stat_mode.
        return os.stat(filename)[0]
    except OSError:
        return 0
output = get_mode('/flash/L76GNSS.py')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'32768\r\n'
-----
----- About to send 396 bytes of code to the pyboard -----
def get_filesize(filename):
    """Returns the size of a file, in bytes."""
    import os
    try:
        # Since this function runs remotely, it can't depend on other functions,
        # so we can't call stat_mode.
        return os.stat(filename)[6]
    except OSError:
        return -1
output = get_filesize('/flash/L76GNSS.py')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'2040\r\n'
-----
----- About to send 1269 bytes of code to the pyboard -----
def send_file_to_host(src_filename, dst_file, filesize):
    """Function which runs on the pyboard. Matches up with recv_file_from_remote."""
    import sys
    import ubinascii
    try:
        with open(src_filename, 'rb') as src_file:
            bytes_remaining = filesize
            if False:
                buf_size = 32
            else:
                buf_size = 32 // 2
            while bytes_remaining > 0:
                read_size = min(bytes_remaining, buf_size)
                buf = src_file.read(read_size)
                if False:
                    sys.stdout.buffer.write(buf)
                else:
                    sys.stdout.write(ubinascii.hexlify(buf))
                bytes_remaining -= read_size
                # Wait for an ack so we don't get ahead of the remote
                while True:
                    char = sys.stdin.read(1)
                    if char:
                        if char == '\x06':
                            break
                        # This should only happen if an error occurs
                        sys.stdout.write(char)
        return True
    except:
        return False
output = send_file_to_host('/flash/L76GNSS.py', None, 2040)
if output is None:
    print("None")
else:
    print(output)

-----
Traceback (most recent call last):
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\pennamen\AppData\Local\Programs\Python\Python38\Scripts\rshell.exe\__main__.py", line 7, in <module>
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\command_line.py", line 4, in main
    rshell.main.main()
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 2966, in main
    real_main()
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 2949, in real_main
    shell.cmdloop(cmd_line)
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 1752, in cmdloop
    stop = self.onecmd(line)
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 1785, in onecmd
    self.onecmd_exec("".join(group))
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 1796, in onecmd_exec
    return cmd.Cmd.onecmd(self, line)
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\cmd.py", line 217, in onecmd
    return func(arg)
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 2211, in do_cp
    if not cp(src_filename, dst_filename):
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 664, in cp
    return src_dev.remote(send_file_to_host, src_dev_filename, dst_file,
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 1497, in remote
    xfer_func(self, *args, **kwargs)
  File "c:\users\pennamen\appdata\local\programs\python\python38\lib\site-packages\rshell\main.py", line 1102, in recv_file_from_remote
    dst_file.write(binascii.unhexlify(write_buf[0:read_size]))
binascii.Error: Non-hexadecimal digit found
davehylands commented 4 years ago

I looked at thisa exact issue back in March (on a private email thread) and the problem appears to stem from a bug in the PyCom firmware. The text of my email from the analysis was:

So it looks like there is a bug of some type in the WiPy version of micropython (and not a bug in rshell).

I updated my WiPy 3.0 board to the latest firmware which reports:
Pycom MicroPython 1.20.2.rc6 [v1.11-01f49f7] on 2020-02-28; WiPy with ESP32
Pybytes Version: 1.3.1

What I observed is that when I issued the cat /flash/main.py command I get the following data coming back on the serial port:

About to open /flash/main.py
bytes_remaining = 34
23206d61696e2e7079202d2d20707574
read_size = 16
Waiting for ACK
Got ACK
bytes_remaining = 18
20796f757220636f6465206865726521
read_size = 16
Waiting for ACK
Got ACK
bytes_remaining = 2
0d0a
read_size = 2
Waiting for ACK
Got ACK
True
\n
\x04\x04
>Guru Meditation Error: Core  0 paniced (StoreProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x40094ca7  PS      : 0x00060233  A0      : 0x80087d40  A1      : 0x3ffb7130  
A2      : 0x00000000  A3      : 0x00060220  A4      : 0x00000001  A5      : 0x0000cdcd  
A6      : 0xb33fffff  A7      : 0x3ffaff34  A8      : 0x0000abab  A9      : 0x3ffb7130  
A10     : 0x00000003  A11     : 0x0000cdcd  A12     : 0x00060220  A13     : 0x0003e37c  
A14     : 0x3f800010  A15     : 0x3f9400d1  SAR     : 0x00000000  EXCCAUSE: 0x0000001d  
EXCVADDR: 0x00000000  LBEG    : 0x40091ac8  LEND    : 0x40091af6  LCOUNT  : 0xffffffff

ELF file SHA256: 0000000000000000000000000000000000000000000000000000000000000000

Backtrace: 0x40094ca7:0x3ffb7130 0x40087d3d:0x3ffb7160 0x40085b15:0x3ffb7180 0x401365ee:0x3ffb71c0 0x400d246c:0x3ffb71e0

================= CORE DUMP START =================
BCMAAAEAAAALAAAAbAEAAA==
kJP9PwCR/T+Ik/0/
AJH9PyCT/T+ifwAA7EH8P+xB/D+Qk/0/5EH8PwEAAADgdfs/4HX7P5CT/T8AAAAA
GAAAAIyD/T9TZXJ2ZXJzAOz1bsT86MQAAQAAAIiT/T8CAAAAIAsGABgAAAADAAAA
FGP7PwAAAAAAAAAAAAAAAAsAAADUZPs/PGX7P6Rl+z8AAAAAAAAAAAEAAAAAAAAA
JIRAPwAAAAA8GAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAE3Q==
YDIIQPC/AEAwCwYAbE0JgMCR/T8AAAAAIwsGACALBgAAAAAAAQAAAAAAAAD//z+z
q6sAAOzc+z8jDwYAkJP9PwEAAAD+AAAAAAAAsBsAAAD//z+zAAAAALzcCEDL3AhA
AAAAAGA0CEABAAAAMGUJQBxl+T8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcOL6PwCS/T97VwmA0JH9P0Td+z8gDwYA
AWQIgPCR/T8BAAAARN37P5CT/T8BAAAA

The \x04\x04 just before the Guru Meditation is micropython coming out of the raw REPL mode. It should then go back to normal (aka friendly REPL mode) and instead its crashing.