在Raspberry PI上使用C#/Mono映射帧缓冲区设备内存时出现问题

在Raspberry PI上使用C#/Mono映射帧缓冲区设备内存时出现问题,c#,raspberry-pi,mono,framebuffer,C#,Raspberry Pi,Mono,Framebuffer,我正在尝试使用通过Mono运行的C#代码直接访问Raspberry Pi上帧缓冲区视频设备的视频内存。我有一个运行良好的C程序,但当我将它移植到C#时,它在“映射到内存”步骤中总是失败 正在运行的C程序(由tasanakorn提供)如下所示: #include <stdio.h> #include <syslog.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h&

我正在尝试使用通过Mono运行的C#代码直接访问Raspberry Pi上帧缓冲区视频设备的视频内存。我有一个运行良好的C程序,但当我将它移植到C#时,它在“映射到内存”步骤中总是失败

正在运行的C程序(由tasanakorn提供)如下所示:

#include <stdio.h>
#include <syslog.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>

#include <bcm_host.h>

int process() {
    DISPMANX_DISPLAY_HANDLE_T display;
    DISPMANX_MODEINFO_T display_info;
    DISPMANX_RESOURCE_HANDLE_T screen_resource;
    VC_IMAGE_TRANSFORM_T transform;
    uint32_t image_prt;
    VC_RECT_T rect1;
    int ret;
    int fbfd = 0;
    char *fbp = 0;

    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;

    bcm_host_init();

    display = vc_dispmanx_display_open(0);
    if (!display) {
        syslog(LOG_ERR, "Unable to open primary display");
        return -1;
    }
    ret = vc_dispmanx_display_get_info(display, &display_info);
    if (ret) {
        syslog(LOG_ERR, "Unable to get primary display information");
        return -1;
    }
    syslog(LOG_INFO, "Primary display is %d x %d", display_info.width, display_info.height);


    fbfd = open("/dev/fb1", O_RDWR);
    if (fbfd == -1) {
        syslog(LOG_ERR, "Unable to open secondary display");
        return -1;
    }
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
        syslog(LOG_ERR, "Unable to get secondary display information");
        return -1;
    }
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
        syslog(LOG_ERR, "Unable to get secondary display information");
        return -1;
    }

    syslog(LOG_INFO, "Second display is %d x %d %dbps\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt);
    if (!screen_resource) {
        syslog(LOG_ERR, "Unable to create screen buffer");
        close(fbfd);
        vc_dispmanx_display_close(display);
        return -1;
    }

    fbp = (char*) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if (fbp <= 0) {
        syslog(LOG_ERR, "Unable to create mamory mapping");
        close(fbfd);
        ret = vc_dispmanx_resource_delete(screen_resource);
        vc_dispmanx_display_close(display);
        return -1;
    }

    vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres);

    while (1) {
        ret = vc_dispmanx_snapshot(display, screen_resource, 0);
        vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8);
        usleep(25 * 1000);
    }

    munmap(fbp, finfo.smem_len);
    close(fbfd);
    ret = vc_dispmanx_resource_delete(screen_resource);
    vc_dispmanx_display_close(display);
}

int main(int argc, char **argv) {
    setlogmask(LOG_UPTO(LOG_DEBUG));
    openlog("fbcp", LOG_NDELAY | LOG_PID, LOG_USER);

    return process();
}
(我在主监视器(也是一个帧缓冲区设备)上尝试了同样的方法,但得到了以下结果——同样的错误。)

错误22是EINVAL,mmap()文档将其描述为“我们不喜欢addr、length或offset(例如,它们太大,或者没有在页面边界上对齐)。”[这也可能意味着:a)length参数为零(不是),或者b)MAP_SHARED和MAP_PRIVATE都设置了(它们不是)]。但是,我传入的值应该与C代码使用的值相同


有人知道我做错了什么吗?

解决了。问题是常量PROT_READ、PROT_WRITE、MAP_SHARED、。。。在覆盆子上,Pi与我通过谷歌搜索(headslap)发现的值不同。我通过查看/usr/include中的.h文件找到了正确的值。此外,我发现mmap的负值不一定是错误;我需要专门寻找MAP_FAILED(-1)

以下是工作代码(如果任何人都可以使用):

using System;
using System.Runtime.InteropServices;

namespace MainProgram {

    class MainClass {

        static void Main(string[] args) {

            int fbfd = -1;  // file descriptor for framebuffer device
            int fbp = -1;   // pointer to mapped framebuffer memory
            uint fbs = 0;   // size of mapped framebuffer memory
            int result = 0; // utility result variable

            try {

            // Initialize (not sure if this is needed, but...).
            Libc.bcm_host_init();

            // Open the device.  (Command line param is device, e.g. "/dev/fb0" or "/dev/fb1".)
            fbfd = Libc.open(args[0], Libc.O_RDWR);
            if (fbfd == -1)
                throw new Exception("open: result=" + fbfd + ", error=" + Marshal.GetLastWin32Error());
            Console.WriteLine("fbfd=" + fbfd);

            // Get fixed screen info.
            Libc.fb_fix_screeninfo fixInfo = new Libc.fb_fix_screeninfo();
            result = Libc.ioctl1(fbfd, Libc.FBIOGET_FSCREENINFO, ref fixInfo);
            if (result == -1)
                throw new Exception("ioctl1: result=" + result + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("fbfix: mem start=" + fixInfo.smem_start.ToString("X8") + ", len=" + fixInfo.smem_len);

            // Get variable screen info.
            Libc.fb_var_screeninfo varInfo = new Libc.fb_var_screeninfo();
            result = Libc.ioctl2(fbfd, Libc.FBIOGET_VSCREENINFO, ref varInfo);
            if (result == -1)
                throw new Exception("ioctl2: result=" + result + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("fbvar: res=" + varInfo.xres + "x" + varInfo.yres + ", bpp=" + varInfo.bits_per_pixel);

            // Map framebuffer memory to virtual space.
            fbp = Libc.mmap(0, fixInfo.smem_len, Libc.PROT_READ | Libc.PROT_WRITE, Libc.MAP_SHARED, fbfd, 0);
            if (fbp == Libc.MAP_FAILED)
                throw new Exception("mmap: result=" + fbp + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("mmap: location=" + fbp.ToString("X8"));
            }

            catch (Exception ex) {
                Console.WriteLine("*** Error: " + ex.Message);
            }

            finally {
                if (fbp != -1)
                    result = Libc.munmap(fbp, fbs);
                if (fbfd != -1)
                    result = Libc.close(fbfd);
            };

        }

        public static class Libc {

            public const int O_RDWR = 0x0002;

            public const int PROT_READ = 0x1;
            public const int PROT_WRITE = 0x2;

            public const int MAP_SHARED = 0x01;

            public const int MAP_FAILED = -1;

            public const int FBIOGET_VSCREENINFO = 0x4600;
            public const int FBIOGET_FSCREENINFO = 0x4602;

            [DllImport("libbcm_host.so", EntryPoint = "bcm_host_init")]
            public static extern void bcm_host_init();

            [DllImport("libc", EntryPoint="open", SetLastError = true)]
            public static extern int open(
                [MarshalAs(UnmanagedType.LPStr)] string filename,
                [MarshalAs(UnmanagedType.I4)] int flags
            );

            [DllImport("libc", EntryPoint="close", SetLastError = true)]
            public static extern int close(
                [MarshalAs(UnmanagedType.I4)] int filedes
            );

            [DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
            public static extern int ioctl1(
                [MarshalAs(UnmanagedType.I4)] int filedes,
                [MarshalAs(UnmanagedType.I4)] int command,
                ref fb_fix_screeninfo data
            );

            [DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
            public static extern int ioctl2(
                [MarshalAs(UnmanagedType.I4)] int filedes,
                [MarshalAs(UnmanagedType.I4)] int command,
                ref fb_var_screeninfo data
            );

            [DllImport("libc", EntryPoint = "mmap", SetLastError = true)]
            public static extern int mmap(
                [MarshalAs(UnmanagedType.U4)] uint addr,
                [MarshalAs(UnmanagedType.U4)] uint length,
                [MarshalAs(UnmanagedType.I4)] int prot,
                [MarshalAs(UnmanagedType.I4)] int flags,
                [MarshalAs(UnmanagedType.I4)] int fdes,
                [MarshalAs(UnmanagedType.I4)] int offset
            );

            [DllImport("libc", EntryPoint = "munmap", SetLastError = true)]
            public static extern int munmap(
                [MarshalAs(UnmanagedType.I4)] int addr,
                [MarshalAs(UnmanagedType.U4)] uint length
            );

            [StructLayout(LayoutKind.Sequential)]
            public struct fb_fix_screeninfo {
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] id;
                [MarshalAs(UnmanagedType.U4)] public uint smem_start;
                [MarshalAs(UnmanagedType.U4)] public uint smem_len;
                [MarshalAs(UnmanagedType.U4)] public uint type;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] stuff;
            };

            [StructLayout(LayoutKind.Sequential)]
            public struct fb_var_screeninfo {
                [MarshalAs(UnmanagedType.U4)] public uint xres;
                [MarshalAs(UnmanagedType.U4)] public uint yres;
                [MarshalAs(UnmanagedType.U4)] public uint xres_virtual;
                [MarshalAs(UnmanagedType.U4)] public uint yres_virtual;
                [MarshalAs(UnmanagedType.U4)] public uint xoffset;
                [MarshalAs(UnmanagedType.U4)] public uint yoffset;
                [MarshalAs(UnmanagedType.U4)] public uint bits_per_pixel;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public byte[] stuff;
            };

        }

    }

}

解决了。问题是常量PROT_READ、PROT_WRITE、MAP_SHARED、。。。在覆盆子上,Pi与我通过谷歌搜索(headslap)发现的值不同。我通过查看/usr/include中的.h文件找到了正确的值。此外,我发现mmap的负值不一定是错误;我需要专门寻找MAP_FAILED(-1)

以下是工作代码(如果任何人都可以使用):

using System;
using System.Runtime.InteropServices;

namespace MainProgram {

    class MainClass {

        static void Main(string[] args) {

            int fbfd = -1;  // file descriptor for framebuffer device
            int fbp = -1;   // pointer to mapped framebuffer memory
            uint fbs = 0;   // size of mapped framebuffer memory
            int result = 0; // utility result variable

            try {

            // Initialize (not sure if this is needed, but...).
            Libc.bcm_host_init();

            // Open the device.  (Command line param is device, e.g. "/dev/fb0" or "/dev/fb1".)
            fbfd = Libc.open(args[0], Libc.O_RDWR);
            if (fbfd == -1)
                throw new Exception("open: result=" + fbfd + ", error=" + Marshal.GetLastWin32Error());
            Console.WriteLine("fbfd=" + fbfd);

            // Get fixed screen info.
            Libc.fb_fix_screeninfo fixInfo = new Libc.fb_fix_screeninfo();
            result = Libc.ioctl1(fbfd, Libc.FBIOGET_FSCREENINFO, ref fixInfo);
            if (result == -1)
                throw new Exception("ioctl1: result=" + result + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("fbfix: mem start=" + fixInfo.smem_start.ToString("X8") + ", len=" + fixInfo.smem_len);

            // Get variable screen info.
            Libc.fb_var_screeninfo varInfo = new Libc.fb_var_screeninfo();
            result = Libc.ioctl2(fbfd, Libc.FBIOGET_VSCREENINFO, ref varInfo);
            if (result == -1)
                throw new Exception("ioctl2: result=" + result + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("fbvar: res=" + varInfo.xres + "x" + varInfo.yres + ", bpp=" + varInfo.bits_per_pixel);

            // Map framebuffer memory to virtual space.
            fbp = Libc.mmap(0, fixInfo.smem_len, Libc.PROT_READ | Libc.PROT_WRITE, Libc.MAP_SHARED, fbfd, 0);
            if (fbp == Libc.MAP_FAILED)
                throw new Exception("mmap: result=" + fbp + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("mmap: location=" + fbp.ToString("X8"));
            }

            catch (Exception ex) {
                Console.WriteLine("*** Error: " + ex.Message);
            }

            finally {
                if (fbp != -1)
                    result = Libc.munmap(fbp, fbs);
                if (fbfd != -1)
                    result = Libc.close(fbfd);
            };

        }

        public static class Libc {

            public const int O_RDWR = 0x0002;

            public const int PROT_READ = 0x1;
            public const int PROT_WRITE = 0x2;

            public const int MAP_SHARED = 0x01;

            public const int MAP_FAILED = -1;

            public const int FBIOGET_VSCREENINFO = 0x4600;
            public const int FBIOGET_FSCREENINFO = 0x4602;

            [DllImport("libbcm_host.so", EntryPoint = "bcm_host_init")]
            public static extern void bcm_host_init();

            [DllImport("libc", EntryPoint="open", SetLastError = true)]
            public static extern int open(
                [MarshalAs(UnmanagedType.LPStr)] string filename,
                [MarshalAs(UnmanagedType.I4)] int flags
            );

            [DllImport("libc", EntryPoint="close", SetLastError = true)]
            public static extern int close(
                [MarshalAs(UnmanagedType.I4)] int filedes
            );

            [DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
            public static extern int ioctl1(
                [MarshalAs(UnmanagedType.I4)] int filedes,
                [MarshalAs(UnmanagedType.I4)] int command,
                ref fb_fix_screeninfo data
            );

            [DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
            public static extern int ioctl2(
                [MarshalAs(UnmanagedType.I4)] int filedes,
                [MarshalAs(UnmanagedType.I4)] int command,
                ref fb_var_screeninfo data
            );

            [DllImport("libc", EntryPoint = "mmap", SetLastError = true)]
            public static extern int mmap(
                [MarshalAs(UnmanagedType.U4)] uint addr,
                [MarshalAs(UnmanagedType.U4)] uint length,
                [MarshalAs(UnmanagedType.I4)] int prot,
                [MarshalAs(UnmanagedType.I4)] int flags,
                [MarshalAs(UnmanagedType.I4)] int fdes,
                [MarshalAs(UnmanagedType.I4)] int offset
            );

            [DllImport("libc", EntryPoint = "munmap", SetLastError = true)]
            public static extern int munmap(
                [MarshalAs(UnmanagedType.I4)] int addr,
                [MarshalAs(UnmanagedType.U4)] uint length
            );

            [StructLayout(LayoutKind.Sequential)]
            public struct fb_fix_screeninfo {
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] id;
                [MarshalAs(UnmanagedType.U4)] public uint smem_start;
                [MarshalAs(UnmanagedType.U4)] public uint smem_len;
                [MarshalAs(UnmanagedType.U4)] public uint type;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] stuff;
            };

            [StructLayout(LayoutKind.Sequential)]
            public struct fb_var_screeninfo {
                [MarshalAs(UnmanagedType.U4)] public uint xres;
                [MarshalAs(UnmanagedType.U4)] public uint yres;
                [MarshalAs(UnmanagedType.U4)] public uint xres_virtual;
                [MarshalAs(UnmanagedType.U4)] public uint yres_virtual;
                [MarshalAs(UnmanagedType.U4)] public uint xoffset;
                [MarshalAs(UnmanagedType.U4)] public uint yoffset;
                [MarshalAs(UnmanagedType.U4)] public uint bits_per_pixel;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public byte[] stuff;
            };

        }

    }

}
$ sudo mono ConsoleApp6.exe /dev/fb0
fbfd=4
fbfix: mem start=1E876000, len=3686400
fbvar: res=1280x720, bpp=32
Confirm non-zero size: fbs=3686400
*** Error: mmap: error 22
using System;
using System.Runtime.InteropServices;

namespace MainProgram {

    class MainClass {

        static void Main(string[] args) {

            int fbfd = -1;  // file descriptor for framebuffer device
            int fbp = -1;   // pointer to mapped framebuffer memory
            uint fbs = 0;   // size of mapped framebuffer memory
            int result = 0; // utility result variable

            try {

            // Initialize (not sure if this is needed, but...).
            Libc.bcm_host_init();

            // Open the device.  (Command line param is device, e.g. "/dev/fb0" or "/dev/fb1".)
            fbfd = Libc.open(args[0], Libc.O_RDWR);
            if (fbfd == -1)
                throw new Exception("open: result=" + fbfd + ", error=" + Marshal.GetLastWin32Error());
            Console.WriteLine("fbfd=" + fbfd);

            // Get fixed screen info.
            Libc.fb_fix_screeninfo fixInfo = new Libc.fb_fix_screeninfo();
            result = Libc.ioctl1(fbfd, Libc.FBIOGET_FSCREENINFO, ref fixInfo);
            if (result == -1)
                throw new Exception("ioctl1: result=" + result + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("fbfix: mem start=" + fixInfo.smem_start.ToString("X8") + ", len=" + fixInfo.smem_len);

            // Get variable screen info.
            Libc.fb_var_screeninfo varInfo = new Libc.fb_var_screeninfo();
            result = Libc.ioctl2(fbfd, Libc.FBIOGET_VSCREENINFO, ref varInfo);
            if (result == -1)
                throw new Exception("ioctl2: result=" + result + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("fbvar: res=" + varInfo.xres + "x" + varInfo.yres + ", bpp=" + varInfo.bits_per_pixel);

            // Map framebuffer memory to virtual space.
            fbp = Libc.mmap(0, fixInfo.smem_len, Libc.PROT_READ | Libc.PROT_WRITE, Libc.MAP_SHARED, fbfd, 0);
            if (fbp == Libc.MAP_FAILED)
                throw new Exception("mmap: result=" + fbp + ", error " + Marshal.GetLastWin32Error());
            Console.WriteLine("mmap: location=" + fbp.ToString("X8"));
            }

            catch (Exception ex) {
                Console.WriteLine("*** Error: " + ex.Message);
            }

            finally {
                if (fbp != -1)
                    result = Libc.munmap(fbp, fbs);
                if (fbfd != -1)
                    result = Libc.close(fbfd);
            };

        }

        public static class Libc {

            public const int O_RDWR = 0x0002;

            public const int PROT_READ = 0x1;
            public const int PROT_WRITE = 0x2;

            public const int MAP_SHARED = 0x01;

            public const int MAP_FAILED = -1;

            public const int FBIOGET_VSCREENINFO = 0x4600;
            public const int FBIOGET_FSCREENINFO = 0x4602;

            [DllImport("libbcm_host.so", EntryPoint = "bcm_host_init")]
            public static extern void bcm_host_init();

            [DllImport("libc", EntryPoint="open", SetLastError = true)]
            public static extern int open(
                [MarshalAs(UnmanagedType.LPStr)] string filename,
                [MarshalAs(UnmanagedType.I4)] int flags
            );

            [DllImport("libc", EntryPoint="close", SetLastError = true)]
            public static extern int close(
                [MarshalAs(UnmanagedType.I4)] int filedes
            );

            [DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
            public static extern int ioctl1(
                [MarshalAs(UnmanagedType.I4)] int filedes,
                [MarshalAs(UnmanagedType.I4)] int command,
                ref fb_fix_screeninfo data
            );

            [DllImport("libc", EntryPoint="ioctl", SetLastError = true)]
            public static extern int ioctl2(
                [MarshalAs(UnmanagedType.I4)] int filedes,
                [MarshalAs(UnmanagedType.I4)] int command,
                ref fb_var_screeninfo data
            );

            [DllImport("libc", EntryPoint = "mmap", SetLastError = true)]
            public static extern int mmap(
                [MarshalAs(UnmanagedType.U4)] uint addr,
                [MarshalAs(UnmanagedType.U4)] uint length,
                [MarshalAs(UnmanagedType.I4)] int prot,
                [MarshalAs(UnmanagedType.I4)] int flags,
                [MarshalAs(UnmanagedType.I4)] int fdes,
                [MarshalAs(UnmanagedType.I4)] int offset
            );

            [DllImport("libc", EntryPoint = "munmap", SetLastError = true)]
            public static extern int munmap(
                [MarshalAs(UnmanagedType.I4)] int addr,
                [MarshalAs(UnmanagedType.U4)] uint length
            );

            [StructLayout(LayoutKind.Sequential)]
            public struct fb_fix_screeninfo {
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] id;
                [MarshalAs(UnmanagedType.U4)] public uint smem_start;
                [MarshalAs(UnmanagedType.U4)] public uint smem_len;
                [MarshalAs(UnmanagedType.U4)] public uint type;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] public byte[] stuff;
            };

            [StructLayout(LayoutKind.Sequential)]
            public struct fb_var_screeninfo {
                [MarshalAs(UnmanagedType.U4)] public uint xres;
                [MarshalAs(UnmanagedType.U4)] public uint yres;
                [MarshalAs(UnmanagedType.U4)] public uint xres_virtual;
                [MarshalAs(UnmanagedType.U4)] public uint yres_virtual;
                [MarshalAs(UnmanagedType.U4)] public uint xoffset;
                [MarshalAs(UnmanagedType.U4)] public uint yoffset;
                [MarshalAs(UnmanagedType.U4)] public uint bits_per_pixel;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public byte[] stuff;
            };

        }

    }

}