Hongmeng OpenHarmony hi3516 development board, standard system response button to take pictures

Since I understand the operation of the standard system GPIO, that is, the Hongmeng OpenHarmony hi3516 development board, the standard system button switches the light , and the next step is to use the button to take pictures. Let’s make a temporary record first. In the next step, study how to call cloud service AI image recognition via http

The overall development method is the same as last time, so it will not be traced back, just modify applications/standard/app/hello.c

Focus on referring to the OpenHarmony documentation and a test source code. The main steps are written in the documentation. In addition, I wrote comments for each step in the code:

Reference document: multimedia_camera_standard: Implementation of camera device management and camera capture functions | Implementation of camera device and camera capture functions

Reference source code: interfaces/innerkits/native/test/camera_capture.cpp · OpenHarmony/multimedia_camera_standard - Gitee.com

The code version used is the master source code of OH2021-12-25. After the new version tag is released recently, I will verify whether the latest version is also OK.

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<poll.h>

#include "input/camera_input.h"
#include "input/camera_manager.h"
#include "surface.h"

#include <cinttypes>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <sstream>

#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>

#include <securec.h>

using namespace std;
using namespace OHOS;
using namespace OHOS::CameraStandard;


#define MSG(args...) printf(args) 
 
//函数声明
static int gpio_export(int pin);
static int gpio_unexport(int pin);
static int gpio_direction(int pin, int dir);
static int gpio_write(int pin, int value);
static int gpio_read(int pin);
static int gpio_edge(int pin, int edge);



static int gpio_export(int pin)  
{  
    char buffer[64];  
    int len;  
    int fd;  
  
    fd = open("/sys/class/gpio/export", O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open export for writing!\n");  
        return(-1);  
    }  
  
    len = snprintf(buffer, sizeof(buffer), "%d", pin);  
    printf("%s,%d,%d\n",buffer,sizeof(buffer),len);
    if (write(fd, buffer, len) < 0) 
    {  
        MSG("Failed to export gpio!");  
        return -1;  
    }  
     
    close(fd);  
    return 0;  
}  
static int gpio_unexport(int pin)  
{  
    char buffer[64];  
    int len;  
    int fd;  
  
    fd = open("/sys/class/gpio/unexport", O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open unexport for writing!\n");  
        return -1;  
    }  
  
    len = snprintf(buffer, sizeof(buffer), "%d", pin);  
    if (write(fd, buffer, len) < 0) 
    {  
        MSG("Failed to unexport gpio!");  
        return -1;  
    }  
     
    close(fd);  
    return 0;  
} 
//dir: 0-->IN, 1-->OUT
static int gpio_direction(int pin, int dir)  
{  
    static const char dir_str[] = "in\0out";  
    char path[64];  
    int fd;  
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin);  
    fd = open(path, O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio direction for writing!\n");  
        return -1;  
    }  
  
    if (write(fd, &dir_str[dir == 0 ? 0 : 3], dir == 0 ? 2 : 3) < 0) 
    {  
        MSG("Failed to set direction!\n");  
        return -1;  
    }  
  
    close(fd);  
    return 0;  
}  
//value: 0-->LOW, 1-->HIGH
static int gpio_write(int pin, int value)  
{  
    static const char values_str[] = "01";  
    char path[64];  
    int fd;  
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);  
    fd = open(path, O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio value for writing!\n");  
        return -1;  
    }  
  
    if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0) 
    {  
        MSG("Failed to write value!\n");  
        return -1;  
    }  
  
    close(fd);  
    return 0;  
}
static int gpio_read(int pin)  
{  
    char path[64];  
    char value_str[3];  
    int fd;  
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);  
    fd = open(path, O_RDONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio value for reading!\n");  
        return -1;  
    }  
  
    if (read(fd, value_str, 3) < 0)
    {  
        MSG("Failed to read value!\n");  
        return -1;  
    }  
  
    close(fd);  
    return (atoi(value_str));
}  
// none表示引脚为输入,不是中断引脚
// rising表示引脚为中断输入,上升沿触发
// falling表示引脚为中断输入,下降沿触发
// both表示引脚为中断输入,边沿触发
// 0-->none, 1-->rising, 2-->falling, 3-->both
static int gpio_edge(int pin, int edge)
{
const char dir_str[] = "none\0rising\0falling\0both"; 
int ptr;
char path[64];  
    int fd; 
switch(edge)
{
    case 0:
        ptr = 0;
        break;
    case 1:
        ptr = 5;
        break;
    case 2:
        ptr = 12;
        break;
    case 3:
        ptr = 20;
        break;
    default:
        ptr = 0;
} 
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", pin);  
    fd = open(path, O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio edge for writing!\n");  
        return -1;  
    }  
  
    if (write(fd, &dir_str[ptr], strlen(&dir_str[ptr])) < 0) 
    {  
        MSG("Failed to set edge!\n");  
        return -1;  
    }  
  
    close(fd);  
    return 0;  
}

enum class mode_ {
    MODE_PREVIEW = 0,
    MODE_PHOTO
};

// 获取当前时间
static uint64_t GetCurrentLocalTimeStamp()
{
    std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp =
        std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
    auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
    return tmp.count();
}

// 保存图片
static int32_t SaveYUV(mode_ mode, const char *buffer, int32_t size)
{
    static const std::int32_t FILE_PERMISSION_FLAG = 00766;
    char path[PATH_MAX] = {0};
    int32_t retVal;

    if (mode == mode_::MODE_PREVIEW) {
        system("mkdir -p /data/preview");
        retVal = sprintf_s(path, sizeof(path) / sizeof(path[0]), "/data/preview/%s_%lld.yuv", "preview",
            GetCurrentLocalTimeStamp());
    } else {
        system("mkdir -p /data/capture");
        retVal = sprintf_s(path, sizeof(path) / sizeof(path[0]), "/data/capture/%s_%lld.jpg", "photo",
            GetCurrentLocalTimeStamp());
    }
    if (retVal < 0) {
        printf("Path Assignment failed");
        return -1;
    }
    printf("%s, saving file to %s", __FUNCTION__, path);
    int imgFd = open(path, O_RDWR | O_CREAT, FILE_PERMISSION_FLAG);
    if (imgFd == -1) {
        printf("%s, open file failed, errno = %s.", __FUNCTION__, strerror(errno));
        return -1;
    }
    int ret = write(imgFd, buffer, size);
    if (ret == -1) {
        printf("%s, write file failed, error = %s.", __FUNCTION__, strerror(errno));
        close(imgFd);
        return -1;
    }
    close(imgFd);
    return 0;
}

// 1.创建缓冲区消费者端监听器(CaptureSurfaceListener)以保存图像。
class CaptureSurfaceListener : public IBufferConsumerListener {
public:
    mode_ mode;
    sptr<Surface> surface_;

    void OnBufferAvailable() override
    {
        int32_t flushFence = 0;
        int64_t timestamp = 0;
        OHOS::Rect damage; // initialize the damage

        OHOS::sptr<OHOS::SurfaceBuffer> buffer = nullptr;
        surface_->AcquireBuffer(buffer, flushFence, timestamp, damage);
        if (buffer != nullptr) {
            char *addr = static_cast<char *>(buffer->GetVirAddr());
            int32_t size = buffer->GetSize();

            // Save the buffer(addr) to a file.
            SaveYUV(mode, addr, size);

            surface_->ReleaseBuffer(buffer, -1);
        }
    }
};


int main()  
{  
    int gpio_fd, ret;
    struct pollfd fds[1];
    char buff[10];
    //41为红灯, 1为1号按键
 
    gpio_unexport(41);
    gpio_unexport(1);
 
    
    //41红灯亮起
    gpio_export(41);
    gpio_direction(41, 1);//output out
    gpio_write(41, 1);
    
    //1按钮初始化
    gpio_export(1);
    gpio_direction(1, 0);//input in
    gpio_edge(1,2);
    gpio_fd = open("/sys/class/gpio/gpio1/value",O_RDONLY);
    if(gpio_fd < 0)
    {
        MSG("Failed to open value!\n");  
        return -1;  
    }
    fds[0].fd = gpio_fd;
    fds[0].events  = POLLPRI;

    // 参考Camera组件拍摄 https://gitee.com/openharmony/multimedia_camera_standard
    // 样例:foundation/multimedia/camera_standard/interfaces/innerkits/native/test/camera_capture.cpp

    // 2.获取相机管理器实例并获取相机对象列表。
    int32_t intResult = -1;
    sptr<CameraManager> camManagerObj = CameraManager::GetInstance();
    std::vector<sptr<CameraInfo>> cameraObjList = camManagerObj->GetCameras();
    if (cameraObjList.size() < 0) {
        printf("No Camera existed! Return -1!");
        return -1;
    }
    for (auto& it : cameraObjList) {
        printf("Camera ID: %s\n", it->GetID().c_str());
    }

    //3. 创建采集会话。
    sptr<CaptureSession> captureSession = camManagerObj->CreateCaptureSession();
    if (captureSession == nullptr) {
        printf("Failed to create capture session");
        return -1;
    }
    //4. 开始配置采集会话。
    captureSession->BeginConfig();

    //5. 使用相机对象创建相机输入。
    sptr<CaptureOutput> photoOutput;
    sptr<CaptureInput> cameraInput = camManagerObj->CreateCameraInput(cameraObjList[0]);
    if (cameraInput != nullptr) {
        //6.将相机输入添加到采集会话。
        intResult = captureSession->AddInput(cameraInput);
        if (intResult == 0) {
            //7.创建消费者Surface并注册监听器以监听缓冲区更新。拍照的宽和高可以配置为所支持的 1280x960 分辨率。
            sptr<Surface> photoSurface = Surface::CreateSurfaceAsConsumer();
            photoSurface->SetDefaultWidthAndHeight(1280, 960);
            sptr<CaptureSurfaceListener> capturelistener = new CaptureSurfaceListener();
            capturelistener->mode = mode_::MODE_PHOTO;
            capturelistener->surface_ = photoSurface;
            photoSurface->RegisterConsumerListener((sptr<IBufferConsumerListener> &)capturelistener);

            //8.使用上面创建的 Surface 创建拍照输出。
            photoOutput = camManagerObj->CreatePhotoOutput(photoSurface);
            if (photoOutput == nullptr) {
                printf("Failed to create PhotoOutput");
                return -1;
            }
            //9.将拍照输出添加到采集会话。
            intResult = captureSession->AddOutput(photoOutput);
            if (intResult != 0) {
                printf("Failed to Add output to session, intResult: %d", intResult);
                return -1;
            }
            //10. 将配置提交到采集会话。
            intResult = captureSession->CommitConfig();
            if (intResult != 0) {
                printf("Failed to Commit config, intResult: %d", intResult);
                return -1;
            }

        }
    }




    
    while(1)
    {

        ret = poll(fds,1,5000);
        if( ret == -1 )
        MSG("poll\n");
        if( fds[0].revents & POLLPRI)
        {
            ret = lseek(gpio_fd,0,SEEK_SET);
            if( ret == -1 )
            MSG("lseek\n");

             ret = read(gpio_fd,buff,10);//读取按钮值,但这里没使用
            if( ret == -1 )
            MSG("read\n");

            //切换红灯
            int status = gpio_read(41);
            printf("41 = %d\n",status);
            gpio_write(41, 1 - status);

            //11.拍摄照片。
            intResult = ((sptr<PhotoOutput> &)photoOutput)->Capture();
            if (intResult != 0) {
                printf("Failed to capture, intResult: %d", intResult);
                return -1;
            }else{
                printf("Success to capture, intResult: %d", intResult);
            }
    
        
            //gpio_write(44, cnt++%2);
            printf("**********************************\n");
        }
        printf("one loop\n");
        //usleep(5);
    }

    //12. 释放采集会话资源。
    captureSession->Release();

    return 0;
}

Build.gn imports the header files and modules of the camera subsystem

import("//build/ohos.gni")
import("//drivers/adapter/uhdf2/uhdf.gni")

ohos_executable("madixin") {
  sources = [
    "madixin.cpp"
  ]
  subsystem_name = "applications"
  part_name = "prebuilt_hap"

  include_dirs = [
    "//foundation/multimedia/camera_standard/interfaces/innerkits/native/camera/include",
    "//foundation/multimedia/camera_standard/interfaces/innerkits/native/test",
    "//foundation/multimedia/camera_standard/services/camera_service/include",
    "//foundation/multimedia/camera_standard/services/camera_service/binder/base/include",
    "//foundation/multimedia/camera_standard/services/camera_service/binder/client/include",
    "//foundation/multimedia/camera_standard/services/camera_service/binder/server/include",
    "//foundation/graphic/standard/frameworks/surface/include",
    "//foundation/multimedia/camera_standard/frameworks/innerkitsimpl/metadata/include",
    "//utils/system/safwk/native/include",
    "//drivers/framework/include/utils",
    "//drivers/adapter/uhdf2/osal/include",
    "//drivers/adapter/uhdf2/include/hdi",
    "//drivers/peripheral/display/interfaces/include",
    "//drivers/peripheral/camera/interfaces/include",
    "//drivers/peripheral/camera/interfaces/hdi_ipc",
    "//drivers/peripheral/camera/interfaces/hdi_ipc/server",
    "//drivers/peripheral/camera/interfaces/hdi_ipc/callback/device",
    "//drivers/peripheral/camera/interfaces/hdi_ipc/callback/operator",
    "//drivers/peripheral/camera/interfaces/hdi_ipc/callback/host",
  ]

 deps = [
    "//foundation/graphic/standard:libsurface",
    "//foundation/multimedia/camera_standard/frameworks/innerkitsimpl/camera:camera_framework",
    "//foundation/multimedia/camera_standard/frameworks/innerkitsimpl/metadata:metadata",
    "//utils/native/base:utils",
  ]
}

Because the photo saving path is defined in CaptureSurfaceListener, that is, the /data/capture directory, so after clicking the button to take a picture, the serial port will output information, and the photo is also saved in the /data/capture directory.

Use the command to send the photo to the machine and then browse and pull it:

hdc_std file recv /data/capture/photo_4942243.jpg D:\madixin\test\images\

source code

MyOpenHarmonySample: My OpenHarmonySample code - Gitee.com

Guess you like

Origin blog.csdn.net/sd2131512/article/details/122179733