0

I am trying to call a C file (dispmanx.c) from a C++ file (main.cpp).

dispmanx.c :

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>

#include "bcm_host.h"

#define WIDTH   200
#define HEIGHT  200

#ifndef ALIGN_UP
#define ALIGN_UP(x,y)  ((x + (y)-1) & ~((y)-1))
#endif

int run(unsigned char* fileData)
{
    typedef struct
    {
        DISPMANX_DISPLAY_HANDLE_T   display;
        DISPMANX_MODEINFO_T         info;
        void                       *image;
        DISPMANX_UPDATE_HANDLE_T    update;
        DISPMANX_RESOURCE_HANDLE_T  resource;
        DISPMANX_ELEMENT_HANDLE_T   element;
        uint32_t                    vc_image_ptr;

    } RECT_VARS_T;

    static RECT_VARS_T  gRectVars;


    RECT_VARS_T    *vars;
    uint32_t        screen = 1;
    int             ret;
    VC_RECT_T       src_rect;
    VC_RECT_T       dst_rect;
    VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565;
    int width = WIDTH, height = HEIGHT;
    int pitch = ALIGN_UP(width*2, 32);
    int aligned_height = ALIGN_UP(height, 16);
    VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 
                             120, /*alpha 0->255*/
                             0 };

    vars = &gRectVars;

    bcm_host_init();

    printf("Open display[%i]...\n", screen );
    vars->display = vc_dispmanx_display_open( screen );

    ret = vc_dispmanx_display_get_info( vars->display, &vars->info);
    assert(ret == 0);
    printf( "Display is %d x %d\n", vars->info.width, vars->info.height );

    vars->image = fileData;

//  vars->image = calloc(1, pitch * height);
    assert(vars->image);

    vars->resource = vc_dispmanx_resource_create( type,
                                                  width,
                                                  height,
                                                  &vars->vc_image_ptr );
    assert( vars->resource );
    vc_dispmanx_rect_set( &dst_rect, 0, 0, width, height);
    ret = vc_dispmanx_resource_write_data(  vars->resource,
                                            type,
                                            pitch,
                                            vars->image,
                                            &dst_rect );


    assert( ret == 0 );
    vars->update = vc_dispmanx_update_start( 10 );
    assert( vars->update );

    vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 );

    vc_dispmanx_rect_set( &dst_rect, ( vars->info.width - width ) / 2,
                                     ( vars->info.height - height ) / 2,
                                     width,
                                     height );

    vars->element = vc_dispmanx_element_add(    vars->update,
                                                vars->display,
                                                2000,               // layer
                                                &dst_rect,
                                                vars->resource,
                                                &src_rect,
                                                DISPMANX_PROTECTION_NONE,
                                                &alpha,
                                                NULL,             // clamp
                                                VC_IMAGE_ROT0 );

    ret = vc_dispmanx_update_submit_sync( vars->update );
    assert( ret == 0 );

    printf( "Sleeping for 10 seconds...\n" );
    sleep( 10 );

    vars->update = vc_dispmanx_update_start( 10 );
    assert( vars->update );
    ret = vc_dispmanx_element_remove( vars->update, vars->element );
    assert( ret == 0 );
    ret = vc_dispmanx_update_submit_sync( vars->update );
    assert( ret == 0 );
    ret = vc_dispmanx_resource_delete( vars->resource );
    assert( ret == 0 );
    ret = vc_dispmanx_display_close( vars->display );
    assert( ret == 0 );

    return 0;
}

#ifdef __cplusplus
}
#endif

the main.cpp:

#include "dispmanx.c"


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;
int main()
{
    Mat image;
    image = imread("t.png", IMREAD_COLOR);   // Read the file
    run(image.data);
}

the code should take an address of a png file get the data of it using OpenCV libraries and pass it to the C program which shows the picture on the screen.

I could compile the dispmanx.c:

pi@raspberrypi:~/openCVtest.1 $ gcc -I/opt/vc/include/
    -I/opt/vc/include/interface/vcos/pthreads
    -I/opt/vc/include/interface/vmcs_host/linux
    -I/opt/vc/src/hello_pi/libs/ilclient
    -I/opt/vc/src/hello_pi/libs/vgfont
    -L/opt/vc/lib/ -L/opt/vc/src/hello_pi/libs/ilclient
    -L/opt/vc/src/hello_pi/libs/vgfont
    -c dispmanx.c
    -o dispmanx.o
    -lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm

but when I try to compile the main.cpp:

pi@raspberrypi:~/openCVtest.1 $ g++ -I/opt/vc/include/     -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/src/hello_pi/libs/ilclient -I/opt/vc/src/hello_pi/libs/vgfont -L/opt/vc/lib/ -L/opt/vc/src/hello_pi/libs/ilclient -L/opt/vc/src/hello_pi/libs/vgfont -c main.cpp dispmanx.o  -o main.o -lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm               In file included from main.cpp:2:0:

dispmanx.c: In function ‘int run(unsigned char*)’: dispmanx.c:52:68: error: invalid conversion from ‘int’ to ‘DISPMANX_FLAGS_ALPHA_T’ [-fpermissive] VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

dispmanx.c:111:63: error: cannot convert ‘VC_IMAGE_TRANSFORM_T’ to ‘DISPMANX_TRANSFORM_T’ for argument ‘10’ to ‘DISPMANX_ELEMENT_HANDLE_T vc_dispmanx_element_add(DISPMANX_UPDATE_HANDLE_T, DISPMANX_DISPLAY_HANDLE_T, int32_t, const VC_RECT_T*, DISPMANX_RESOURCE_HANDLE_T, const VC_RECT_T*, DISPMANX_PROTECTION_T, VC_DISPMANX_ALPHA_T*, DISPMANX_CLAMP_T*, DISPMANX_TRANSFORM_T)’
                                             VC_IMAGE_ROT0 );

I have tested both program separately and the function as they should, however when I tried to mix them I get errors that I cant understand.

I am a student have beginner level of knowledge. what am I doing wrong?

1
  • You might want to show where line 111 in dispmanx.c is. It's possible to count to 111 and find it, but better make it easier to readers by marking // The error is here or something like that. You can edit your question to do it. Commented Aug 16, 2018 at 10:33

2 Answers 2

1

Given these contents of dispmanx.c:

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>

and main.cpp starts with

#include "dispmanx.c"

You are going to have serious problems.

You've wrapped entire standard header files such as unistd.h with extern "C", and then #include'd them in a C++ file.

They're not meant to be used that way in C++ code.

#include'ing a source file (.c, .cpp, etc) is a fundamentally bad idea in the first place. Doing it across different languages such a C and C++ and then improperly wrapping system headers with extern "C" is even worse. You can't safely compile C code as C++ code, and you certainly can't wrap system header files with extern "C" for use in C++ code.

extern "C" does not make it safe to compile C code with a C++ compiler. They are different languages, with subtle distinctions.

Sign up to request clarification or add additional context in comments.

7 Comments

In fairness, those are all C headers and possibly have #ifdef/extern "C" combos of their own
Thank you very useful info, if wrapping with extern "c" is not a good approach what do you suggest for a fix to my problem? would it be a better option if i create a main method for the dispmanx.c and tried a wrapper for my cpp code(which contains OpenCV libraries)?
@LightnessRacesinOrbit But the Linux glibc stdio.h header starts with the comment Define ISO C stdio on top of C++ iostreams. I'm not going through all that trying to figure out what wrapping something like that with extern "C" does when included in a C++ source file.
@AndrewHenle I don't know what that comment's doing there, but it's implausible that glibc I/O is a wrapper around the C++ standard library's IOstreams.
@Ben You compile your C code with a C compiler, your C++ code with a C++ compiler, than you can link them together. See stackoverflow.com/questions/31903005/… for an example.
|
1

The problem is here:

#include "dispmanx.c"

Including a *.c file in a *.cpp file is not a good idea. C and C++ are similar languages, so it may look that it works at first (i.e. the compiler reports the error not at line 1 but at line 111), but actually it doesn't.

One correct way to call C code from C++ code is by providing a declaration like this:

// C++ code
#include <iostream>

extern "C" {
    int run(unsigned char* fileData); // declaration for the C code
}

...
int main()
{
    ...
    run(image.data); // calling the C code
}

The declaration for the C code can be in the *.cpp file or, more conventionally, in a separate dedicated *.h file. If your C code is in dispmanx.c, then a conventional name is dispmanx.h:

// dispmanx.h
extern "C" {
    int run(unsigned char* fileData); // declaration for the C code
}
// main.cpp
#include <iostream>
#include "dispmanx.h"
...
int main()
{
    ...
    run(image.data); // calling the C code
}

Also, another convention: if you want to make your new dispmanx.h file compilable in both C and C++, you should hide the extern "C" part from the C compiler, as described in this question and answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.