diff --git a/ESP32_PrusaConnectCam/camera.cpp b/ESP32_PrusaConnectCam/camera.cpp index ac30a88..0adc728 100644 --- a/ESP32_PrusaConnectCam/camera.cpp +++ b/ESP32_PrusaConnectCam/camera.cpp @@ -29,6 +29,8 @@ Camera::Camera(Configuration* i_conf, Logs* i_log, uint8_t i_FlashPin) { CameraFlashPin = i_FlashPin; StreamOnOff = false; frameBufferSemaphore = xSemaphoreCreateMutex(); + FrameBufferDuplicate = (camera_fb_t*)heap_caps_malloc(sizeof(camera_fb_t), MALLOC_CAP_SPIRAM); + StreamSendingPhoto = false; PhotoExifData.header = NULL; PhotoExifData.len = 0; @@ -397,6 +399,13 @@ void Camera::CapturePhoto() { ledcWrite(FLASH_PWM_CHANNEL, FLASH_OFF_STATUS); } xSemaphoreGive(frameBufferSemaphore); + + } else { + /* Stream is on, set flag for sending photo */ + if (xSemaphoreTake(frameBufferSemaphore, portMAX_DELAY)) { + StreamSendingPhoto = true; + xSemaphoreGive(frameBufferSemaphore); + } } /* Reinit camera module if photo capture failed */ @@ -426,6 +435,40 @@ void Camera::CaptureStream(camera_fb_t* i_buf) { /* check if photo is correctly saved */ } while (!(FrameBuffer->len > 100)); *i_buf = *FrameBuffer; + + /* copy the frame buffer to the duplicate frame buffer. For sending photo to Prusa Connect */ + if (false == StreamSendingPhoto) { + /* memory allocation release */ + if (FrameBufferDuplicate != NULL) { + if (FrameBufferDuplicate->buf != NULL) { + free(FrameBufferDuplicate->buf); + FrameBufferDuplicate->buf = NULL; /* Set to NULL after freeing */ + } + + free(FrameBufferDuplicate); + FrameBufferDuplicate = NULL; /* Set to NULL after freeing */ + } + + /* Allocate memory for the duplicate frame structure */ + FrameBufferDuplicate = (camera_fb_t*)heap_caps_malloc(sizeof(camera_fb_t), MALLOC_CAP_SPIRAM); + + /* Copy the metadata */ + memcpy(FrameBufferDuplicate, FrameBuffer, sizeof(camera_fb_t)); + + /* Allocate memory for the image data */ + FrameBufferDuplicate->buf = (uint8_t*)heap_caps_malloc(FrameBuffer->len, MALLOC_CAP_SPIRAM); + + /* Check if memory allocation was successful */ + if (!FrameBufferDuplicate->buf) { + /* Handle error */ + free(FrameBufferDuplicate); + Serial.println("Failed to allocate memory for the duplicate frame buffer"); + } else { + /* Copy the image data */ + memcpy(FrameBufferDuplicate->buf, FrameBuffer->buf, FrameBuffer->len); + } + } + xSemaphoreGive(frameBufferSemaphore); } } @@ -508,6 +551,15 @@ void Camera::StreamClearFrameData() { StreamAverageSize = 0; } +/** + @brief Set Sending Photo for Stream + @param bool - sending photo + @return none +*/ +void Camera::StreamSetSendingPhoto(bool i_data) { + StreamSendingPhoto = i_data; +} + /** @brief Get Photo @param none @@ -530,6 +582,15 @@ camera_fb_t* Camera::GetPhotoFb() { return FrameBuffer; } +/** + @brief Get Photo Frame Buffer Duplicate + @param none + @return camera_fb_t* - photo frame buffer duplicate +*/ +camera_fb_t* Camera::GetPhotoFbDuplicate() { + return FrameBufferDuplicate; +} + /** @brief Get Photo Exif Data @param none diff --git a/ESP32_PrusaConnectCam/camera.h b/ESP32_PrusaConnectCam/camera.h index c014a3c..ed65126 100644 --- a/ESP32_PrusaConnectCam/camera.h +++ b/ESP32_PrusaConnectCam/camera.h @@ -68,9 +68,11 @@ class Camera { /* OV2640 camera module pinout and cfg*/ camera_config_t CameraConfig; ///< camera configuration camera_fb_t *FrameBuffer; ///< frame buffer + camera_fb_t *FrameBufferDuplicate; ///< frame buffer duplicate sensor_t* sensor; ///< sensor String Photo; ///< photo in string format bool StreamOnOff; ///< stream on/off + bool StreamSendingPhoto; ///< sending photo to Prusa Connect during stream SemaphoreHandle_t frameBufferSemaphore; ///< semaphore for frame buffer float StreamAverageFps; ///< stream average fps uint16_t StreamAverageSize; ///< stream average size @@ -104,6 +106,7 @@ class Camera { uint16_t StreamGetFrameAverageSize(); float StreamGetFrameAverageFps(); void StreamClearFrameData(); + void StreamSetSendingPhoto(bool); void CopyPhoto(camera_fb_t *); void CopyPhoto(String*); @@ -112,6 +115,7 @@ class Camera { int GetPhotoSize(); String GetPhoto(); camera_fb_t *GetPhotoFb(); + camera_fb_t* GetPhotoFbDuplicate(); PhotoExifData_t * GetPhotoExifData(); framesize_t TransformFrameSizeDataType(uint8_t); void SetPhotoSending(bool); diff --git a/ESP32_PrusaConnectCam/connect.cpp b/ESP32_PrusaConnectCam/connect.cpp index d0e283f..de433d2 100644 --- a/ESP32_PrusaConnectCam/connect.cpp +++ b/ESP32_PrusaConnectCam/connect.cpp @@ -126,8 +126,17 @@ bool PrusaConnect::SendDataToBackend(String *i_data, int i_data_length, String i /* get photo buffer */ bool SendWithExif = false; - uint8_t *fbBuf = camera->GetPhotoFb()->buf; - size_t fbLen = camera->GetPhotoFb()->len; + uint8_t *fbBuf = NULL; + size_t fbLen = 0; + if (camera->GetStreamStatus() == true) { + /* get duplicate photo buffer from camera */ + fbBuf = camera->GetPhotoFbDuplicate()->buf; + fbLen = camera->GetPhotoFbDuplicate()->len; + } else { + /* get original photo buffer from camera */ + fbBuf = camera->GetPhotoFb()->buf; + fbLen = camera->GetPhotoFb()->len; + } /* sending exif data */ if ((camera->GetPhotoExifData()->header != NULL) && (camera->GetStreamStatus() == false)) { @@ -235,8 +244,10 @@ void PrusaConnect::SendPhotoToBackend() { if ((camera->GetPhotoExifData()->header != NULL) && (camera->GetStreamStatus() == false)) { total_len = camera->GetPhotoExifData()->len + camera->GetPhotoFb()->len - camera->GetPhotoExifData()->offset; - } else { + } else if (camera->GetStreamStatus() == false) { total_len = camera->GetPhotoFb()->len; + } else { + total_len = camera->GetPhotoFbDuplicate()->len; } SendDataToBackend(&Photo, total_len, F("image/jpg"), F("Photo"), HOST_URL_CAM_PATH, SendPhoto); camera->SetPhotoSending(false); @@ -302,8 +313,13 @@ void PrusaConnect::TakePictureAndSendToBackend() { log->AddEvent(LogLevel_Error, F("Error capturing photo. Stop sending to backend!")); } + /* return frame buffer */ if (camera->GetStreamStatus() == false) { + /* return frame buffer when photo is not sent during stream */ camera->CaptureReturnFrameBuffer(); + } else { + /* set stream flag for sending photo to false */ + camera->StreamSetSendingPhoto(false); } }