Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The invocation of C++ by Supervisor fails. #1658

Open
lovechang1986 opened this issue Sep 12, 2024 · 0 comments
Open

The invocation of C++ by Supervisor fails. #1658

lovechang1986 opened this issue Sep 12, 2024 · 0 comments

Comments

@lovechang1986
Copy link

Operating system environment:

  1. Jetpack 6.0.
  2. Ubuntu 22.04.
  3. aarch64.

First, I have a C++ program for a Hikvision industrial camera. It calls the XOpenDisplay function of the X11 library to start a window and display the video stream of the camera. After compiling it, using ./Display or /bin/bash -c "/opt/MVS/Samples/aarch64/Display/Display" in the terminal can both start the window and see the video stream.
Next, I encapsulated it using the following Python code to provide an API for access. After starting the FastAPI service through the following command /usr/bin/python /root/main.py in the terminal, accessing this API can also normally start the window and see the video stream.

However, when I assign the task of starting the FastAPI web service to supervisor. After starting the web service normally, calling the API service prompts please run with screen environment. It can be found that an execution error occurs on the line of code dpy = XOpenDisplay(NIL);, which causes it to output the prompt.
Finally, what should I do to enable the Python application managed by supervisor to call the C++ compiled program normally using subprocess?

Attempts made:

  1. Add environment variables, such as DISPLAY=:0.

  2. Output the value of the current environment variable DISPLAY as :0 inside Dispaly.cpp to confirm that the environment variable is correct.

  3. Ensure that the code for starting the Python script is a shell script and use the supervisor configuration of command=/bin/bash -c "/usr/bin/python /path/to/my/python/main.py", but it still doesn't work.

  4. Use xhost + to allow all the user can connect to X server.

The following is the FastAPI web code(main.py).

from fastapi import FastAPI
import subprocess as sp
app = FastAPI()


@app.get('/test_hik')
def test_hik():
    cmd = f'/bin/bash -c "/path/to/the/hik/Display"'
    import os
    # sp.call(cmd, shell=True, cwd = config.DISPLAY_PATH.parent, env=dict(os.environ, DISPLAY=":0", XAUTHORITY="/home/jetson/.xsessionrc"))
    sp.call(cmd, shell=True, cwd = config.DISPLAY_PATH.parent)
    return {'status':True, 'msg':'Success start window grab images...'}


if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app)

The following is the supervisor configuration.

[program:pollen]
autorestart=True
autostart=True
redirect_stderr=True
command=/bin/bash -c "DISPLAY=:0  /bin/bash /path/to/my/python/main.sh"
user=root
directory=/root/pollen_new
stdout_logfile_maxbytes=20MB
stdout_logfile_backups=20
stdout_logfile=/var/log/pollen.log
environment=DISPLAY=":0",MVCAM_SDK_PATH="/opt/MVS",MVCAM_COMMON_RUNENV="/opt/MVS/lib",MVCAM_GENICAM_CLPROTOCOL="/opt/MVS/lib/CLProtocol",ALLUSERSPROFILE="/opt/MVS/MVFG"

The following is the Display C++ codes.

#include <X11/Xlib.h> 
#include <assert.h>  
#include "math.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include "MvCameraControl.h"

#define NIL (0) 

bool g_bExit = false;
Window g_hwnd;

// 等待用户输入enter键来结束取流或结束程序
// wait for user to input enter to stop grabbing or end the sample program
void PressEnterToExit(void)
{
    int c;
    while ( (c = getchar()) != '\n' && c != EOF );
    fprintf( stderr, "\nPress enter to exit.\n");
    while( getchar() != '\n');
    g_bExit = true;
    sleep(1);
}

bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
{
    if (NULL == pstMVDevInfo)
    {
        printf("The Pointer of pstMVDevInfo is NULL!\n");
        return false;
    }
    if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE)
    {
        int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
        int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
        int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
        int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);

        // ch:打印当前相机ip和用户自定义名字 | en:print current ip and user defined name
        printf("Device Model Name: %s\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);
        printf("CurrentIp: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);
        printf("UserDefinedName: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
    }
    else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
    {
        printf("Device Model Name: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName);
        printf("UserDefinedName: %s\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
    }
    else
    {
        printf("Not support.\n");
    }

    return true;
}

static void* WorkThread(void* pUser)
{
    int nRet = MV_OK;
    MV_FRAME_OUT stImageInfo = {0};
    MV_DISPLAY_FRAME_INFO stDisplayInfo = {0};

    while(1)
    {
        nRet = MV_CC_GetImageBuffer(pUser, &stImageInfo, 1000);
        if (nRet == MV_OK)
        {
            //printf("Get Image Buffer: Width[%d], Height[%d], FrameNum[%d]\n", stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, stImageInfo.stFrameInfo.nFrameNum);

            if (g_hwnd)
            {
                stDisplayInfo.hWnd = (void*)g_hwnd;
                stDisplayInfo.pData = stImageInfo.pBufAddr;
                stDisplayInfo.nDataLen = stImageInfo.stFrameInfo.nFrameLen;
                stDisplayInfo.nWidth = stImageInfo.stFrameInfo.nWidth;
                stDisplayInfo.nHeight = stImageInfo.stFrameInfo.nHeight;
                stDisplayInfo.enPixelType = stImageInfo.stFrameInfo.enPixelType;

                MV_CC_DisplayOneFrame(pUser, &stDisplayInfo);
            }

            nRet = MV_CC_FreeImageBuffer(pUser, &stImageInfo);
            if(nRet != MV_OK)
            {
                printf("Free Image Buffer fail! nRet [0x%x]\n", nRet);
            }
        }
        else
        {
            printf("Get Image fail! nRet [0x%x]\n", nRet);
        }
        if(g_bExit)
        {
            break;
        }
    }

    return 0;
}

int main()
{     
    Display *dpy; 

    memset(&g_hwnd, 0, sizeof(Window));
    dpy    = NULL;

    // 打开连接到X服务器的连接
    // open the connection to the display 0
    dpy = XOpenDisplay(NIL);

    if (NULL == dpy)
    {
        printf("please run with screan environment\n");
        return -1;
    }

    int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));

    g_hwnd = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 
        752, 480, 0, 0xffff00ff, 0xff00ffff);

    // 获取改变窗口大小事件 
    // we want to get MapNotify events
    XSelectInput(dpy, g_hwnd, StructureNotifyMask |ExposureMask | KeyPressMask);

    // 使窗口可见
    // "Map" the window (that is, make it appear on the screen)
    XMapWindow(dpy, g_hwnd);

    // 创建图像上下文给出绘图函数的属性
    // Create a "Graphics Context"
    GC gc = XCreateGC(dpy, g_hwnd, 0, NIL);

    // 告诉GC使用白色
    // Tell the GC we draw using the white color
    XSetForeground(dpy, gc, whiteColor);

    // 等待事件的到来
    // Wait for the MapNotify event
    for(;;) 
    {
        XEvent e;
        XNextEvent(dpy, &e);
        if (e.type == MapNotify)
        {
            break;
        }
    }

    int nRet = MV_OK;

    void* handle = NULL;
    do 
    {
        MV_CC_DEVICE_INFO_LIST stDeviceList;
        memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));

        // 枚举设备
        // enum device
        nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
        if (MV_OK != nRet)
        {
            printf("MV_CC_EnumDevices fail! nRet [%x]\n", nRet);
            break;
        }

        if (stDeviceList.nDeviceNum > 0)
        {
            for (int i = 0; i < stDeviceList.nDeviceNum; i++)
            {
                printf("[device %d]:\n", i);
                MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
                if (NULL == pDeviceInfo)
                {
                    break;
                } 
                PrintDeviceInfo(pDeviceInfo);            
            }  
        } 
        else
        {
            printf("Find No Devices!\n");
            break;
        }

      //  printf("Please Intput camera index: ");
        unsigned int nIndex = 0;
     //   scanf("%d", &nIndex);

        if (nIndex >= stDeviceList.nDeviceNum)
        {
            printf("Intput error!\n");
            break;
        }

        // 选择设备并创建句柄
        // select device and create handle
        nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
        if (MV_OK != nRet)
        {
            printf("MV_CC_CreateHandle fail! nRet [%x]\n", nRet);
            break;
        }

        // 打开设备
        // open device
        nRet = MV_CC_OpenDevice(handle);
        if (MV_OK != nRet)
        {
            printf("MV_CC_OpenDevice fail! nRet [%x]\n", nRet);
            break;
        }

        // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
        if (stDeviceList.pDeviceInfo[nIndex]->nTLayerType == MV_GIGE_DEVICE)
        {
            int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
            if (nPacketSize > 0)
            {
                nRet = MV_CC_SetIntValue(handle,"GevSCPSPacketSize",nPacketSize);
                if(nRet != MV_OK)
                {
                    printf("Warning: Set Packet Size fail nRet [0x%x]!\n", nRet);
                }
            }
            else
            {
                printf("Warning: Get Packet Size fail nRet [0x%x]!\n", nPacketSize);
            }
        }


        // 设置float型变量
        // set IFloat variable
        float fAcquisitionFrameRate = 20.0f;

        nRet = MV_CC_SetFloatValue(handle, "AcquisitionFrameRate", fAcquisitionFrameRate);
        if (MV_OK == nRet)
        {
            printf("set AcquisitionFrameRate OK!\n\n");
        }
        else
        {
            printf("set AcquisitionFrameRate failed! nRet [%x]\n\n", nRet);
        }

        // 设置int型变量  height
        // set IInteger variable
        unsigned int nHeightValue = 1080;

        // 宽高设置时需考虑步进(16),即设置宽高需16的倍数
        // Step (16) should be considered when setting width and height, that is the width and height should be a multiple of 16
        nRet = MV_CC_SetIntValue(handle, "Height", nHeightValue);    
        if (MV_OK == nRet)
        {
            printf("set height OK!\n\n");
        }
        else
        {
            printf("set height failed! nRet [%x]\n\n", nRet);
        }

        unsigned int nWidthValue = 1440;

        // 宽高设置时需考虑步进(16),即设置宽高需16的倍数
        // Step (16) should be considered when setting width and height, that is the width and height should be a multiple of 16
        nRet = MV_CC_SetIntValue(handle, "Width", nWidthValue);    
        if (MV_OK == nRet)
        {
            printf("set width OK!\n\n");
        }
        else
        {
            printf("set width failed! nRet [%x]\n\n", nRet);
        }

        // 设置bool型变量
        // set IBoolean variable
        bool bAcquisitionFrameRateEnable = true;
        nRet = MV_CC_SetBoolValue(handle, "AcquisitionFrameRateEnable", bAcquisitionFrameRateEnable);
        if (MV_OK == nRet)
        {
            printf("Set AcquisitionFrameRateEnable OK!\n\n");
        }
        else
        {
            printf("Set AcquisitionFrameRateEnable Failed! nRet = [%x]\n\n", nRet);
        }

        // 设置enum型变量 ExposureAuto
        // set IEnumeration variable
        unsigned int nExposureAuto = 2;//Continuous
        nRet = MV_CC_SetEnumValue(handle, "ExposureAuto", nExposureAuto);
        if (MV_OK == nRet)
        {
            printf("set ExposureAuto OK!\n\n");
        }
        else
        {
            printf("set ExposureAuto failed! nRet [%x]\n\n", nRet);
        }


        // 设置int型变量  AutoExposureTimeUpperLimit
        // set IInteger variable
        unsigned int nAutoExposureTimeUpperLimit = 25000;
        nRet = MV_CC_SetIntValue(handle, "AutoExposureTimeUpperLimit", nAutoExposureTimeUpperLimit);    
        if (MV_OK == nRet)
        {
            printf("set AutoExposureTimeUpperLimit OK!\n\n");
        }
        else
        {
            printf("set AutoExposureTimeUpperLimit failed! nRet [%x]\n\n", nRet);
        }



        // 开始取流
        // start grab image
        nRet = MV_CC_StartGrabbing(handle);
        if (MV_OK != nRet)
        {
            printf("MV_CC_StartGrabbing fail! nRet [%x]\n", nRet);
            break;
        }

        pthread_t nThreadID;
        nRet = pthread_create(&nThreadID, NULL ,WorkThread , handle);
        if (nRet != 0)
        {
            printf("thread create failed.ret = %d\n",nRet);
            break;
        }

        XEvent event;

        fprintf( stderr, "\nPress q to exit.\n");
        while (1) {
                XNextEvent(dpy, &event);
                if (event.type == Expose) {
                    // Draw or redraw the window here
                } else if (event.type == KeyPress) {
                    KeySym keysym = XLookupKeysym(&event.xkey, 0);
                    if (keysym == 'q') {
                        printf("Quitting...\n");
                        g_bExit = true;

                        break;
                    }
                }

                sleep(1);
    }




     //   PressEnterToExit();

        // 停止取流
        // stop grab image
        nRet = MV_CC_StopGrabbing(handle);
        if (MV_OK != nRet)
        {
            printf("MV_CC_StopGrabbing fail! nRet [%x]\n", nRet);
            break;
        }

        // 关闭设备
        // close device
        nRet = MV_CC_CloseDevice(handle);
        if (MV_OK != nRet)
        {
            printf("MV_CC_CloseDevice fail! nRet [%x]\n", nRet);
            break;
        }

        // 销毁句柄
        // destroy handle
        nRet = MV_CC_DestroyHandle(handle);
        if (MV_OK != nRet)
        {
            printf("MV_CC_DestroyHandle fail! nRet [%x]\n", nRet);
            break;
        }
        handle = NULL;
    }while (0);


    if (handle != NULL)
    {
        MV_CC_DestroyHandle(handle);
        handle = NULL;
    }
    printf("exit.\n");

    return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant