Trouble sending binary file from PC top Pico (sys.stdin.buffer)

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
Post Reply
electronut
Posts: 6
Joined: Mon Dec 13, 2021 3:01 am

Trouble sending binary file from PC top Pico (sys.stdin.buffer)

Post by electronut » Wed May 18, 2022 10:51 am

I am trying to send binary files from my laptop to a Pico board uploaded with the following firmware: rp2-pico-20220117-v1.18.uf2

Here is the code that sends the file:

Code: Select all

# send.py
import os
import serial
import struct
import time
import sys

# serial port
port = "COM4"
# open serial 
ser = serial.Serial(port, 115200)

# file name
filename = sys.argv[1]
    
file_size = os.path.getsize(filename)
print("File size = {} bytes.".format(file_size))

f = open(filename, "rb")

# send file size in 32 bit header
header = struct.pack('<L', file_size)
ser.write(header)
ser.flush()

# send file in chunks
chunk_size = 1024
try:
    nbytes = 0
    while True:
        bytes = f.read(chunk_size)
        nbytes += len(bytes)
        if not bytes:
            print("done, break.")
            break
        ser.write(bytes)
        ser.flush()
        print("wrote {} bytes...".format(nbytes))
except Exception as e:
    print(e)

print("closing...")
ser.close() 
f.close()

Here's the code on the Pico:

Code: Select all

import time
import sys
import os
from machine import Pin
import struct

# 2 - esp32, 25, pico
PIN_LED = 25

def blink(pin_led, nblink):
    for i in range(nblink):
        pin_led.value(1)
        time.sleep(0.25)
        pin_led.value(0)
        time.sleep(0.25)

def main():
    # set up LED
    pin_led = Pin(PIN_LED, Pin.OUT)
    pin_led.value(0)
    
    f = open("recv.bin", "wb")
    
    try:
        
        # get file size in 4 byte header
        header = sys.stdin.buffer.read(4)
        #print(header)
        file_size = struct.unpack('<L', header)[0]
        
        # get rest of the data
        chunk_size = 1024
        n_chunks = file_size // chunk_size
        remaining = file_size - (n_chunks * chunk_size)
        
        blink(pin_led, 2)
        
        # create byte array and manage memory
        ba = bytearray(chunk_size)
        
        nbytes = 0
        for i in range(n_chunks):
            data = sys.stdin.buffer.read(chunk_size)
            f.write(data)
            
        # get remaining bytes < chunk_size
        data = sys.stdin.buffer.read(remaining)
        f.write(data)
    except Exception as e:
        # not reached
        blink(pin_led, 4)
            
    pin_led.value(1)
    
    # close file
    f.close()
        
    
if __name__ == "__main__":
    main()
The strange thing is that some binary files go through fine and some are causing the Pico to block on read.

If I create a file as below, the data goes through fine:

Code: Select all

>>> f = open("104090a.bin", "wb")
>>> data = bytearray(b'a'*104090)
>>> f.write(data)
104090
>>> f.close()
But I fill it with random bytes, it gets stuck on read on the Pico:

Code: Select all

>>> import numpy as np
>>> f = open("104090r.bin", "wb")
>>> data = bytearray(np.random.bytes(104090))
>>> f.write(data)
104090
>>> f.close()
For a "real" file (a binary FPGA bitstream of 104090 bytes, the sending fails, which is why ran the above experiments.)

Why does it get stuck?

I am guessing it has to with the encoding, or I must be messing something else up. Any suggestions appreciated. Thanks!

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Trouble sending binary file from PC top Pico (sys.stdin.buffer)

Post by Roberthh » Wed May 18, 2022 10:58 am

sys.stdint.read and the unbuffered sister are not fully transparent. The still would cancel on the Ctrl-C character \x03. You can disable Ctrl-C detection with by

import micropython
micropython.kbd_intr(-1)

electronut
Posts: 6
Joined: Mon Dec 13, 2021 3:01 am

Re: Trouble sending binary file from PC top Pico (sys.stdin.buffer)

Post by electronut » Wed May 18, 2022 11:17 am

import micropython
micropython.kbd_intr(-1)
That worked great! Thank you so much! :)

Post Reply