c++ – Configure virtual USB drive, quickly copy the images/files from a Virtual USB disc/drive which are saved by a passive device

I have project to work with a camera which is design to capture color images in front view and back n white images from side angles. In this case, camera device has 2 cameras
Front camera is a UVC camera which capture color images. other camera is capturing 2 black and white images for the same capture
Color camera is directly connected to the image analyzing system which is running a UVC driver and the item recognizing application.
Black and White image capturing camera is connected to the analyzing system via an OTG cable. These 2 camera integrated unit is a single device which has a Type C USB output port and general USB 2/3 port.
if we directly plug a flash drive to the unit, black and white images directly saved to the flash drive. that is the method they provided to transfer the image files from the camera unit. I need to receive all the images to my analyzing system to compare. So I created a virtual USB driver using the USB-OTG concepts described in “https://unix.stackexchange.com/questions/120368/make-a-computer-act-as-a-virtual-usb-device-for-other-equipments” post.
so, I’m using a Raspberry Pi/Jetson-nano system as the analyzing computer and photo recognizing application is running in the system.
enter image description here

In this case, my verification application is receiving color images via USB cable. with the event, I’m receiving the image file names for the relevant other 2 black and white images. black and white images are directly saving to the Virtual USB disc prepared in the Raspberry Pi Unit.

without running the application, I can see all the black and white images inside the virtual USB device. I wrote following code to retrieve/copy the images from virtual USB device (Mass storage of the camera unit).

I used following program to receive the images.

#include <iostream>
#include <fstream>
#include <vector>
#include <memory>
#include <cstdio>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>

#include "device_manager.h"

#include "cc_camera_camera_manager_client.h"
#include "cc_camera_camera_client.h"
#include "camera_enums.h"

using namespace std;
using namespace cc_camera;

int MassStorageOperation(cc_camera::camera_sdk::ImageEventMetaData md);
int CopyBlackAndWhiteImages(cc_camera::camera_sdk::ImageEventMetaData md);
int AccessStorage();
void ToggleStorage(std::string src_mount_device, std::string target_mount_point, int inter_operation_delay);


class AttachedEventObserver: public DeviceAttachedListener
{
public:
    void Attached(DeviceInfo info) override
    {
        printf("--- %s: vid/pid %0x:%0x bus/addr %0x:%0x %sn",
                __func__,
                info.vid, info.pid,
                info.bus_number, info.device_address,
                info.serial_number.c_str());
    }
};

class DetachedEventObserver: public DeviceDetachedListener
{
public:
    void Detached(DeviceInfo info) override
    {
        printf("--- %s: vid/pid %0x:%0x bus/addr %0x:%0x %sn",
                __func__,
                info.vid, info.pid,
                info.bus_number, info.device_address,
                info.serial_number.c_str());
    }
};


class DecodeImageEventObserver: public cc_camera::camera_sdk::DecodeImageEventListener
{
private:
    cc_camera::camera_sdk::ImageEventMetaData first_image_meta_data;
    bool very_first_decode;
    int decode_count;
public: 
    DecodeImageEventObserver()
    {
        very_first_decode = true;
        decode_count = 0;
    }
    void ImageReceived(cc_camera::camera_sdk::ImageEventData image_data, cc_camera::camera_sdk::ImageEventMetaData md)
    {
        printf("-- DecodeImageEventObserver: Image event received... count:%dn", decode_count);
        printf("--- Image number: %d", md.image_number);
        printf(" - Decode_data: %sn", md.decode_data.c_str());
        
        usleep(750*1000);
        MassStorageOperation(md);

    }
};

int AccessStorage()
{
    std::string src_storage_device = "/dev/sbcblk0p15";
    std::string dest_mount_point = "/media/cc_camera/VUSB_FLASH";
    std::string cc_camera_decode_dir = "cc_camera_DecodeImages";
    
    int status = 0;    
    bool is_mounted = false;
    
    status = umount2(src_storage_device.c_str(), MNT_FORCE);
    
    if(status == 0)
    {
        printf("--- Storage un-mounted...n");
    }
    else
    {
        printf("-*** umount failed: source storage: %s - destination mount point: %s - failure: (%d)(%s)n", 
                            src_storage_device.c_str(), dest_mount_point.c_str(), errno, strerror(errno));
        return errno;
    }
    
    
    status = mount(src_storage_device.c_str(), dest_mount_point.c_str(), "vfat", 0, "");
    if(status == 0)
    {
        usleep(100*1000);
        status = mount(src_storage_device.c_str(), dest_mount_point.c_str(), "vfat", 0, "");
        is_mounted = true;
        printf("--- Storage mounted...n");        
                
    }
    else
    {
        printf("-*** Mount failed: source storage: %s - destination mount point: %s - failure: (%d)(%s)n", 
                            src_storage_device.c_str(), dest_mount_point.c_str(), errno, strerror(errno));
        return errno;
    }
    
    status = umount2(src_storage_device.c_str(), MNT_FORCE);
    
    if(status != 0)
    {
        is_mounted = true;
        printf("----- Storage un-mounted...n");
    }
    else
    {
        printf("-***** umount failed: source storage: %s - destination mount point: %s - failure: (%d)(%s)n", 
                            src_storage_device.c_str(), dest_mount_point.c_str(), errno, strerror(errno));
        return errno;
    }
    
    return status;
}

int MountStorage(std::string src_mount_device, std::string target_mount_point)
{
    int status = 0;    
    bool is_mounted = false;
    int retry_count = 0;
    std::string unmount_command = "umount -l " + src_mount_device;
    
    status = mount(src_mount_device.c_str(), target_mount_point.c_str(), "vfat", 0, "");
    if(status == 0)
    {
        printf("--- Storage mounted...n");
        is_mounted = true;                  
    }
    else
    {
        printf("- *** Mount failed: source storage: %s - destination mount point: %s - failure: (%d)(%s)n", 
                            src_mount_device.c_str(), target_mount_point.c_str(), errno, strerror(errno));
                                
        status = system(unmount_command.c_str());
        if(status == 0)
        {
            printf("--- system:Storage un-mounted...n");
        }
        else if(status < 0 && errno != EINVAL)
        {
            printf("-*** system:umount failed: unmount_command: %s - failure: (%d)(%s)n", 
                                unmount_command.c_str(), errno, strerror(errno));
        }
        
        retry_count = 20;
        while( retry_count > 0) {
            usleep(100*1000);
            status = mount(src_mount_device.c_str(), target_mount_point.c_str(), "vfat", 0, "");
            if(status == 0)
            {
                printf("--- Storage mounted after retry...n");
                is_mounted = true;             
                
                break;
                
            } else {
                printf("- *** Mount failed: retry count=%d, source storage: %s - destination mount point: %s - failure: (%d)(%s)n", 
                            retry_count, src_mount_device.c_str(), target_mount_point.c_str(), errno, strerror(errno));
            }
            retry_count--;
        }
       
       if(!is_mounted){
            return errno;
        }
    }
    
    return 0;
}

int UmountStorage(std::string src_mount_device)
{
    int status = 0;    
    bool is_mounted = false;
    int retry_count = 0;
    std::string unmount_command = "umount -l " + src_mount_device;
    
    status = system(unmount_command.c_str());
    if(status == 0)
    {
        is_mounted = false;
        printf("--- system:Storage un-mounted...n");
    }
    else if(status < 0 && errno != EINVAL)
    {
        printf("-*** system:umount failed: unmount_command: %s - failure: (%d)(%s)n", 
                            unmount_command.c_str(), errno, strerror(errno));
                                
        retry_count = 30;
        while( retry_count > 0) {
            usleep(200*1000);
            status = system(unmount_command.c_str());
            if(status == 0)
            {
                printf("--- system:Storage un-mounted after retry...n");
                is_mounted = false;             
                
                break;
                
            }
            retry_count--;
        }
        //return errno;
    } else if (errno == EINVAL)
    {
        printf("-*** system:umount failed: unmount_command: %s - failure: (%d)(%s)n", 
                            unmount_command.c_str(), errno, strerror(errno));
                            
    }
    
    
    /**
     * int mount(const char *source, const char *target,
     *              const char *filesystemtype, 
     *              unsigned long mountflags,
     *              const void *data);
     */
    
    
    status = umount2(src_mount_device.c_str(), MNT_DETACH);
    if(status != 0)
    {
        is_mounted = true;
        printf("--- Storage un-mounted...n");
    }
    else
    {
        printf("-*** umount failed: source storage: %s - failure: (%d)(%s)n", 
                            src_mount_device.c_str(), errno, strerror(errno));
        
        retry_count = 5;
        while( retry_count > 0) {
            usleep(100*1000);
            status = umount2(src_mount_device.c_str(), MNT_FORCE);
            if(status == 0)
            {
                printf("--- Storage un-mounted after retry...n");
                is_mounted = true;             
                
                break;
                
            }
            retry_count--;
        }
        
        return errno;
    }
    
}



int MassStorageOperation(cc_camera::camera_sdk::ImageEventMetaData md)
{
    std::string target_mount_point = "/media/user/VFLASH";
    std::string src_mount_device = "/dev/sdablk0p15";
    std::string image_dir = "BW_Images";
    
    int status = 0;    
    bool is_mounted = false;
    int retry_count = 0;
         
    
    // Unmount the storage
    status = UmountStorage(src_mount_device);
    
    /// Let MP7 to finish trasferring image data.
    usleep(250*1000); 
    
    // Then mount the storage
    status = MountStorage(src_mount_device, target_mount_point);
    
    
    /// now successfully mounted///
    CopyBlackAndWhiteImages(md);
        
    
    printf("--- Storage access completed...n");
    return true;
}

void ToggleStorage(std::string src_mount_device, std::string target_mount_point, int inter_operation_delay)
{
    for(int x=0; x<6; x++) {
        UmountStorage(src_mount_device);
        usleep(inter_operation_delay*1000);
        MountStorage(src_mount_device, target_mount_point);
    }
}

int CopyBlackAndWhiteImages(cc_camera::camera_sdk::ImageEventMetaData md)
{   
    std::string target_mount_point = "/media/cc_camera/MP7FLASH";
    std::string src_mount_device = "/dev/mmcblk0p15";
    std::string image_dir = "cc_camera_DecodeImages";
    
    std::string dest_dir = "./";    
    std::string image_extension = ".jpg";
    std::string bw_image2_path = target_mount_point + "/" + image_dir + "/" + md.decode_data + "_T" + image_extension;    
    std::string bw_image2_path_local = "./" + md.decode_data + image_extension;
    std::string bw_image1_path = target_mount_point + "/" + image_dir + "/" + md.decode_data + "_P" + image_extension;
    std::string bw_image1_path_local = "./" + md.decode_data + image_extension;
    
    printf("--- BW iamge 2: %sn--- BW iamge 1: %sn", bw_image2_path.c_str(), bw_image1_path.c_str());
    
    FILE *image_original_t, *image_copy_t, *image_original_p, *image_copy_p;

    
    // copy tower image
    ToggleStorage(src_mount_device, target_mount_point, 1);
    if(access(bw_image2_path.c_str(), F_OK) != 0)
    {
        /// refresh the storage
        int retry_count = 5;
        while(retry_count > 0 && access(bw_image2_path.c_str(), F_OK) != 0){
            printf("---*BW iamge 2 not ready n");          
            UmountStorage(src_mount_device);
            usleep(250*1000);
            MountStorage(src_mount_device, target_mount_point);
            retry_count--;
        }
    }
    
    if(access(bw_image2_path.c_str(), F_OK) == 0)
    {
        printf("---- BW iamge 2 is availablen");
        
        image_original_t = fopen(bw_image2_path.c_str(), "rb");       
        if(image_original_t == NULL)
        {
            printf("-*** BW iamge 2: Error opening file - ");
            printf("failure: (%d)(%s)n", errno, strerror(errno));
        }

        image_copy_t = fopen(bw_image2_path_local.c_str(), "wb");
        if(image_copy_t == NULL)
        {
            printf("-*** Local BW iamge 2: Error opening file - ");
            printf("failure: (%d)(%s)n", errno, strerror(errno));
        }

        struct stat file_stat;
        int read_point = 0;
                
        if(!image_original_t || !image_copy_t)
        {
            printf("--- File Error...n");
        } else {
            long file_size;
            fseek(image_original_t, 0, SEEK_END);
            file_size = ftell(image_original_t);
            rewind(image_original_t);
            unsigned char *file_buffer = (unsigned char *)malloc(sizeof(unsigned char) * file_size);
            if(NULL == file_buffer)
            {
                printf("--- Memory errorn");
            }
            printf("---- file size: %dn", file_size);


            size_t result = fread(file_buffer, 1, file_size, image_original_t);
            
            result = fwrite(file_buffer, sizeof(unsigned char), file_size, image_copy_t);
            
            free(file_buffer);
            
            fclose(image_original_t);
            fclose(image_copy_t);
        }
    } else
    {
        printf("---- BW iamge 2 is not OKn");
    }
    
    /// Copy platter image      
    ToggleStorage(src_mount_device, target_mount_point, 1);
        
    if(access(bw_image1_path.c_str(), F_OK) != 0)
    {
        int retry_count = 5;
        while(retry_count > 0 && access(bw_image1_path.c_str(), F_OK) != 0){
            printf("---*BW iamge 1 image not ready n");            
            UmountStorage(src_mount_device);
            usleep(250*1000);
            MountStorage(src_mount_device, target_mount_point);
            retry_count--;
        }
    }
    
    if(access(bw_image1_path.c_str(), F_OK) == 0)
    {
        printf("---- BW iamge 1 is availablen");
        
        image_original_p = fopen(bw_image1_path.c_str(), "r");
        if(image_original_p == NULL)
        {
            printf("-*** BW iamge 1: Error opening file - ");
            printf("failure: (%d)(%s)n", errno, strerror(errno));
        }
        
        image_copy_p = fopen(bw_image1_path_local.c_str(), "w");
        if(image_copy_p == NULL)
        {
            printf("-*** BW iamge 1: Error opening file - ");
            printf("failure: (%d)(%s)n", errno, strerror(errno));
        }

        if(!image_original_p || !image_copy_p)
        {
            printf("--- File Error...n");
        } else {
            
            struct stat file_stat;
            int read_point = 0;
                    
            if(!image_original_p || !image_copy_p)
            {
                printf("--- File Error...n");
            } else {
                
                long file_size;
                fseek(image_original_p, 0, SEEK_END);
                file_size = ftell(image_original_p);
                rewind(image_original_p);
                unsigned char *file_buffer = (unsigned char *)malloc(sizeof(unsigned char) * file_size);
                if(NULL == file_buffer)
                {
                    printf("--- Memory errorn");
                }
                printf("---- file size: %dn", file_size);


                size_t result = fread(file_buffer, 1, file_size, image_original_p);
                
                result = fwrite(file_buffer, sizeof(unsigned char), file_size, image_copy_p);
                
                free(file_buffer);
                
                fclose(image_original_p);
                fclose(image_copy_p);
            }

        }
    } else
    {
        printf("---- BW iamge 1 is not OKn");
    }    

    printf("--- File operations completed...n");
}

int main() {

    cout << "------------------------------------------------------------------------" << endl;
        cout << "---- Ticket switching : copy black and white images to local storage----" << endl;
        cout << "---- Press any key and Enter to exit------------------------------------" << endl;
        cout << "------------------------------------------------------------------------" << endl;

    int i;

    DeviceManager device_mgr;

    auto devinfolist = device_mgr.EnumerateDevices();


    for (auto info: devinfolist)
    {
        printf("---- Device info: vid/pid %0x:%0x bus/addr %0x:%0x %sn",
                info.vid, info.pid,
                info.bus_number, info.device_address,
                info.serial_number.c_str());
    }

    cout << "---- Number of connected cameras = " << devinfolist.size() << endl;

    if (0 == devinfolist.size())
    {
        exit(0);
    }

        cc_camera::DeviceManager device_manager;
    std::unique_ptr<cc_camera::camera_sdk::cc_cameraCameraManagerClient> cammgr = cc_camera::camera_sdk::Createcc_cameraCameraManagerClient();

    cout << "---- Constructed: camera manager client" << endl;
    //cin >> i;
        
        AttachedEventObserver attach_event_observer;
        DetachedEventObserver dettach_event_observer;
        device_manager.AddDeviceAttachedListener(attach_event_observer);
        device_manager.AddDeviceDetachedListener(dettach_event_observer);

    std::shared_ptr<cc_camera::camera_sdk::cc_cameraCameraClient> camera = cammgr->Createcc_cameraCamera(devinfolist(0));

    cout << "---- Constructed: camera client" << endl;
    usleep(100*1000);
        
        // register for image events
        ProduceImageEventObserver produce_image_event_observer;
        DecodeImageEventObserver decode_event_observer;
                
        camera->AddProduceImageEventListener(produce_image_event_observer);
        camera->AddDecodeImageEventListener(decode_event_observer);
        
        // block here for user input to exit.
        cin >> i;
        cout << "-----------Program interrupted-----------------------------------------" << endl;
        
        camera->RemoveProduceImageEventListener(produce_image_event_observer);
        camera->RemoveDecodeImageEventListener(decode_event_observer);
        device_manager.RemoveDeviceAttachedListener(attach_event_observer);
        device_manager.RemoveDeviceDetachedListener(dettach_event_observer); 
        
        cout << "------------------------------------------------------------------------" << endl;
                
    return 0;
}

With this approach, I have to use several delays (usleeps()) and multiple mass storage unmout-mount operations. Otherwise, the images saving to mass storage is getting corrupted.

Is this approach correct ? I couldn’t find out better solutions.