• Script EMMC access

I'm trying to follow this code sample to access the eMMC, but I'm getting the error below.

First, I verified that I have eMMC:

./bootloader_version.py 
Found device with name: 192.168.2.241
Version: 0.0.26
NETWORK Bootloader, is User Bootloader: False
Memory 'Memory.FLASH' size: 16777216, info: JEDEC ID: 01 20 18
Memory 'Memory.EMMC' size: 15758000128, info: 

(Note that I get nothing after 'info:' on the EMMC line above.

Second, I enabled the eMMC:

import depthai as dai

# Create pipeline
pipeline = dai.Pipeline()

# Set board config
board = dai.BoardConfig()
board.emmc = True
config = dai.Device.Config()
config.board = board
pipeline.setBoardConfig(board)

(f, bl) = dai.DeviceBootloader.getFirstAvailableDevice()
bootloader = dai.DeviceBootloader(bl)
progress = lambda p : print(f'Flashing progress: {p*100:.1f}%')
(r, errmsg) = bootloader.flash(progress, pipeline, memory=dai.DeviceBootloader.Memory.EMMC)
if r: print("Flash OK")

Now, when I run the example without modification:

import depthai as dai
import cv2

# Start defining a pipeline
pipeline = dai.Pipeline()

board = dai.BoardConfig()
board.emmc = True
pipeline.setBoardConfig(board)

# Define source and output
camRgb = pipeline.create(dai.node.ColorCamera)
jpegEncoder = pipeline.create(dai.node.VideoEncoder)

# Properties
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_4_K)
jpegEncoder.setDefaultProfilePreset(1, dai.VideoEncoderProperties.Profile.MJPEG)

#Set a write script
script_write = pipeline.createScript()
script_write.setProcessor(dai.ProcessorType.LEON_CSS)
script_write.setScript("""

    import os
    index = 1000
    import time
    while True:
        # Find an unused file name first
        while True:
            path = '/media/mmcsd-0-0/' + str(index) + '.jpg'
            if not os.path.exists(path):
                break
            index += 1
        frame = node.io['jpeg'].get()
        node.warn(f'Saving to EMMC: {path}')
        with open(path, 'wb') as f:
            f.write(frame.getData())
        index += 1
        time.sleep(3)

""")
                      
#Set a read script
script_read = pipeline.createScript()
script_read.setProcessor(dai.ProcessorType.LEON_CSS)
script_read.setScript("""

    import http.server
    import socketserver
    import socket
    import fcntl
    import struct
    import os

    def get_ip_address(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            -1071617759,  # SIOCGIFADDR
            struct.pack('256s', ifname[:15].encode())
        )[20:24])

    # Note: `chdir` here will prevent unmount, this should be improved!
    os.chdir('/media/mmcsd-0-0')

    PORT = 80
    Handler = http.server.SimpleHTTPRequestHandler

    with socketserver.TCPServer(("", PORT), Handler) as httpd:
        ip = get_ip_address('re0')
        node.warn(f'===== HTTP file server accessible at: http://{ip}')
        httpd.serve_forever()

""")
                      
# Linking

camRgb.video.link(jpegEncoder.input)
jpegEncoder.bitstream.link(script_write.inputs['jpeg'])
script_write.inputs['jpeg'].setBlocking(False)
xout = pipeline.create(dai.node.XLinkOut)
xout.setStreamName("rgb")
script_read.outputs['jpeg'].link(xout.input)


# Pipeline defined, now the device is connected to
with dai.Device(pipeline) as device:
    # Output queue will be used to get the rgb frames from the output defined above
    qRgb = device.getOutputQueue(name="rgb", maxSize=100, blocking=False)

    while True:
        inRgb = qRgb.tryGet() 
        
        if inRgb is not None:
            cv2.imshow("rgb", inRgb.getCvFrame())
            
        if cv2.waitKey(1) == ord('q'):
            break

I get this error:

(.venv) ~/code/people-counter/try/luxonis/eMMC >  python script_emmc_access.py 
[1844301021D93E1300] [192.168.2.241] [5.683] [Script(2)] [warning] Saving to EMMC: /media/mmcsd-0-0/1000.jpg
[1844301021D93E1300] [192.168.2.241] [5.683] [Script(2)] [critical] FileNotFoundError: [Errno 2] N: '/media/mmcsd-0-0/1000.jpg'

At:
  <script>(24): <module>

Traceback (most recent call last):
  File "Users/user/code/people-counter/try/luxonis/eMMC/script_emmc_access.py", line 101, in <module>
    inRgb = qRgb.tryGet() 
RuntimeError: Communication exception - possible device error/misconfiguration. Original message 'Couldn't read data from stream: 'rgb' (X_LINK_ERROR)'

Thoughts?

To eliminate the FileNotFoundError, which I'm guessing is caused by this line:

         with open(path, 'wb') as f:

I modified the example code to this minimal version, which just starts a webserver in a script node:

# oak_filesystem.py

import depthai as dai
import cv2

# Start defining a pipeline
pipeline = dai.Pipeline()

board = dai.BoardConfig()
board.emmc = True
pipeline.setBoardConfig(board)

#Set a read script
script_read = pipeline.createScript()
script_read.setProcessor(dai.ProcessorType.LEON_CSS)
script_read.setScript("""

    import http.server
    import socketserver
    import socket
    import fcntl
    import struct
    import os

    def get_ip_address(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            -1071617759,  # SIOCGIFADDR
            struct.pack('256s', ifname[:15].encode())
        )[20:24])

    # Note: `chdir` here will prevent unmount, this should be improved!
    os.chdir('/media/mmcsd-0-0')

    PORT = 80
    Handler = http.server.SimpleHTTPRequestHandler

    with socketserver.TCPServer(("", PORT), Handler) as httpd:
        ip = get_ip_address('re0')
        node.warn(f'===== HTTP file server accessible at: http://{ip}')
        httpd.serve_forever()

""")
                      
# Pipeline defined, now the device is connected to
with dai.Device(pipeline) as device:
    while True:
        if cv2.waitKey(1) == ord('q'):
            break

Now, I get this error:

[1844301021D93E1300] [192.168.2.241] [5.971] [Script(0)] [critical] FileNotFoundError: [Errno 2] N: '/media/mmcsd-0-0'

At:
  <script>(19): <module>

which I'm guessing is caused by this line:
    os.chdir('/media/mmcsd-0-0')

and if I comment out the os.chdir line, I get no errors, but when I browse the device IP address, I get:

which clearly does not have a path of /media/mmcsd-0-0

which is probably due to the note above that line.

Thoughts?

    Hi Craftonix
    Not being able to access /media/mmcsd-0-0 means the EMMC memory has not been enabled correctly. Could you try reruning the enable script (mostly just setting board config and not having any webserver inside the app).

    Thanks,
    Jaka

    I tried the exact steps above more than 10 times before posting this.

    Please answer each of my numbered questions:

    1. Have you tried my EXACT steps above and copy-paste my EXACT code?
    2. Should the output line Memory 'Memory.EMMC' size: 15758000128, info:have any info at the end of the line? Because my output has nothing after info:
    3. Why do we need this code:
    # Note: `chdir` here will prevent unmount, this should be improved!
    os.chdir('/media/mmcsd-0-0')

    and why do you do it only in the webserver script node, and not in the other script node as well?

    1. If it is needed, then could there be a race-condition where the other script starts but the eMMC is not mounted yet?
    2. Some example code has config = dai.Device.Config() config.board = board and other example code doesn't. Is it needed when running?
    3. If it is already enabled by the first code I provided from the documentation, then why do we need this:
    board = dai.BoardConfig()
    board.emmc = True
    pipeline.setBoardConfig(board)

    again when running the pipeline?

    a month later

    Hi Craftonix

    1. I have not tried your exact code, but I have verified again that the guide in the docs works. I'll test it on a different device as well, since both tests were done on OAK-D-POE, just to be sure.

    2. The info is empty on my side as well.

    3, 4. Good question. If the eMMC is not mounted when the script_read node starts, the HTTP server might not serve the expected files. Does anything change if you add the mount in the other script?

    5, 6. board = dai.BoardConfig()
    board.emmc = True
    pipeline.setBoardConfig(board)
    This is the main part. Without it, emmc won't be accessible at all. It basically tells the board each time to enable the access to emmc, which is disabled by default.

    ps. Apologies for the late reply, I was on vacation at the time and the thread got lost.

    Thanks,
    Jaka