VOXL OpenVINS Server 0.7.0
Visual Inertial Odometry Server for VOXL Platform
Loading...
Searching...
No Matches
CameraBase.cpp
Go to the documentation of this file.
1/**
2 * @file CameraBase.cpp
3 * @brief Base camera implementation for VOXL OpenVINS
4 * @author Joao Leonardo Silva Cotta (@zauberflote1)
5 * @date 2025
6 * @version 1.0
7 *
8 * This file implements the base camera functionality for the VOXL OpenVINS system.
9 * It provides the foundation for camera handling, pipe communication, image
10 * processing, and VIO integration.
11 *
12 * The implementation handles:
13 * - Camera pipe connection and management
14 * - Image data reception and processing
15 * - OpenCL context setup for GPU acceleration
16 * - Thread-safe operations with mutex protection
17 * - ION buffer handling for efficient memory management
18 * - Callback management for image data reception
19 */
20
21#include "CameraBase.h"
22
23#include "VoxlVars.h"
24
25#include <unistd.h>
26#include <modal_flow/ocl/OclDevice.hpp>
27#include <CL/cl_ext.h>
28#include <sys/mman.h> // mmap
29
30namespace voxl
31{
32
33 /**
34 * @brief Constructor for CameraBase
35 *
36 * Initializes a camera instance with the provided configuration information.
37 * Sets up the camera with default values and prepares it for connection.
38 *
39 * @param camera_info Camera configuration and calibration information
40 */
41 CameraBase::CameraBase(const cam_info &camera_info)
42 : camera_info_(camera_info)
43 {
44 }
45
46 /**
47 * @brief Connect to the camera pipe service
48 *
49 * This method establishes the connection to the camera pipe service
50 * and sets up the necessary callbacks for image data reception.
51 *
52 * The connection process includes:
53 * - Obtaining an available pipe channel
54 * - Configuring appropriate callbacks
55 * - Opening the pipe connection with proper flags and buffer size
56 * - Flushing the pipe to clear stale data
57 *
58 * @return true if connection was successful, false otherwise
59 */
61 {
62 std::lock_guard<std::mutex> lock(mutex_);
63
64 if (is_connected_)
65 {
66 std::cerr << "Camera " << camera_info_.name << " is already connected" << std::endl;
67 return true;
68 }
69
70 // Get the next available channel
71 channel_ = pipe_client_get_next_available_channel();
72 if (channel_ < 0)
73 {
74 std::cerr << "Failed to get available channel for camera " << camera_info_.name << std::endl;
75 vio_error_codes |= ERROR_CODE_CAM_MISSING;
76 return false;
77 }
78
79 static const char suffix[] = "_ion";
80 size_t len = strnlen(camera_info_.tracking_name, 128); // safe length
81 size_t sfx = sizeof(suffix) - 1; // 4
82
83 int flags, pipe_size;
84
85 if (len >= sfx && memcmp(camera_info_.tracking_name + (len - sfx), suffix, sfx) == 0)
86 {
87 pipe_client_set_ion_buf_helper_cb(channel_, CameraBase::camera_device_buffer_callback, this);
88
89 flags = CLIENT_FLAG_EN_ION_BUF_HELPER;
90 pipe_size = 0;
91 }
92 else
93 {
94 // Set the camera callback
95 pipe_client_set_camera_helper_cb(channel_, CameraBase::camera_callback, this);
96
97 flags = CLIENT_FLAG_EN_CAMERA_HELPER;
98 pipe_size = 1280 * 800 * 15;
99 }
100
101 int ret = pipe_client_open(channel_, camera_info_.tracking_name, PROCESS_NAME, flags, pipe_size);
102
103 if (ret != 0)
104 {
105 std::cerr << "Failed to open camera pipe: " << camera_info_.tracking_name << std::endl;
106 vio_error_codes |= ERROR_CODE_CAM_MISSING;
107 return false;
108 }
109
110 if (en_debug)
111 {
112 std::cout << "Successfully connected to camera: " << camera_info_.name
113 << " (channel: " << channel_ << ")" << std::endl;
114 }
115
116 // Flush the pipe to clear any stale data
117 pipe_client_flush(channel_);
118
119 is_connected_ = true;
120 return true;
121 }
122
123 /**
124 * @brief Disconnect and clean up resources
125 *
126 * This method properly closes the pipe connection and cleans up
127 * any allocated resources. It ensures a clean shutdown of the
128 * camera connection.
129 *
130 * The disconnection process includes:
131 * - Flushing the pipe to clear pending data
132 * - Waiting for pending operations to complete
133 * - Closing the pipe connection
134 * - Updating connection state
135 *
136 * The method is thread-safe and handles cases where the camera
137 * is already disconnected.
138 */
140 {
141 std::lock_guard<std::mutex> lock(mutex_);
142
143 if (!is_connected_)
144 {
145 return;
146 }
147
148 // Flush pipe to clear pending data
149 if (en_debug)
150 {
151 printf("Flushing pipe for primary channel: %d\n", channel_);
152 }
153 pipe_client_flush(channel_);
154
155 // Small delay to ensure pending operations complete
156 usleep(50000);
157
158 is_connected_ = false;
159
160 if (en_debug)
161 {
162 std::cout << "Disconnected camera: " << camera_info_.name << std::endl;
163 }
164 }
165
166 /**
167 * @brief Common callback function for pipe client
168 *
169 * This function receives raw image data from the pipe and dispatches
170 * it to the appropriate processing method. It serves as the entry
171 * point for all camera data processing.
172 *
173 * The callback performs the following operations:
174 * - Enables thread cancellation for proper cleanup
175 * - Validates the camera context pointer
176 * - Checks for global shutdown conditions
177 * - Dispatches to the derived class process_image method
178 *
179 * @param ch Channel number (unused)
180 * @param meta Image metadata containing timestamp and format information
181 * @param frame Pointer to image data buffer
182 * @param context Context pointer (the CameraBase instance)
183 */
184 void CameraBase::camera_callback(int ch, camera_image_metadata_t meta, char *frame, void *context)
185 {
186 // Enable thread cancellation
187 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
188 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
189
190 // Cast the context pointer back to a CameraBase pointer
191 CameraBase *camera = static_cast<CameraBase *>(context);
192
193 // Make sure we have a valid camera instance
194 if (!camera)
195 {
196 std::cerr << "Invalid camera context in callback" << std::endl;
197 vio_error_codes |= ERROR_CODE_CAM_MISSING;
198 return;
199 }
200
201 // Early check for global shutdown flag
202 if (!main_running)
203 {
204 return;
205 }
206
207 // Process the image in the derived class implementation
208 camera->process_image(meta, voxl::ImageType::CV_MAT, frame);
209 }
210
211 void CameraBase::camera_device_buffer_callback(int ch, mpa_ion_buf_t *data, void *context)
212 {
213 // Enable thread cancellation
214 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
215 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
216
217 // Cast the context pointer back to a CameraBase pointer
218 CameraBase *camera = static_cast<CameraBase *>(context);
219
220 // Make sure we have a valid camera instance
221 if (!camera)
222 {
223 std::cerr << "Invalid camera context in callback" << std::endl;
224 vio_error_codes |= ERROR_CODE_CAM_MISSING;
225 return;
226 }
227
228 if (is_resetting.load(std::memory_order_relaxed))
229 return;
230
231 // Early check for global shutdown flag
232 if (!main_running)
233 return;
234
235 auto meta = data->img_meta;
236
237 cl_int err = CL_SUCCESS;
238 if (!camera->ctx_)
239 camera->ctx_ = modal_flow::ocl::OclDevice::Instance().context();
240 if (!camera->q_)
241 camera->q_ = clCreateCommandQueue(camera->ctx_, modal_flow::ocl::OclDevice::Instance().device(), 0, &err);
242 if (err != CL_SUCCESS)
243 {
244 fprintf(stderr, "clCreateCommandQueue err=%d\n", err);
245 return;
246 }
247
248 void *frame = mmap(NULL, data->size, PROT_READ | PROT_WRITE, MAP_SHARED, data->fd, 0);
249 if (frame == MAP_FAILED)
250 {
251 perror("mmap");
252 return;
253 }
254 cl_mem_ion_host_ptr cl_mem_ptr;
255 memset(&cl_mem_ptr, 0, sizeof(cl_mem_ion_host_ptr));
256 cl_mem_ptr.ext_host_ptr.allocation_type = CL_MEM_ION_HOST_PTR_QCOM;
257 cl_mem_ptr.ext_host_ptr.host_cache_policy = CL_MEM_HOST_UNCACHED_QCOM; // CL_MEM_HOST_WRITEBACK_QCOM; //CL_MEM_HOST_UNCACHED_QCOM;
258 cl_mem_ptr.ion_filedesc = data->fd;
259 cl_mem_ptr.ion_hostptr = frame;
260
261 cl_int err_code;
262 cl_mem cl_mem_out = clCreateBuffer(camera->ctx_,
263 CL_MEM_HOST_NO_ACCESS | CL_MEM_USE_HOST_PTR | CL_MEM_EXT_HOST_PTR_QCOM,
264 data->size,
265 &cl_mem_ptr,
266 &err_code);
267
268 if (err_code != CL_SUCCESS)
269 {
270 fprintf(stderr, "Error: clCreateBuffer failed with code %d\n", err_code);
271 }
272
273 cl_mem cl_mem_dest = clCreateBuffer(camera->ctx_,
274 CL_MEM_HOST_NO_ACCESS | CL_MEM_READ_ONLY,
275 data->size,
276 NULL,
277 &err_code);
278 if (err_code != CL_SUCCESS)
279 {
280 fprintf(stderr, "Error: clCreateBuffer failed for destination buffer with code %d\n", err_code);
281 }
282
283 err_code = clEnqueueCopyBuffer(camera->q_,
284 cl_mem_out, // Source buffer (ION-backed memory)
285 cl_mem_dest, // Destination buffer (GPU memory)
286 0, 0, // Source and destination offsets
287 meta.height * meta.width * sizeof(uint8_t), // Size
288 0, nullptr, nullptr);
289 if (err_code != CL_SUCCESS)
290 {
291 fprintf(stderr, "Error: clEnqueueCopyBuffer failed with code %d\n", err_code);
292 }
293 clFinish(camera->q_);
294 clReleaseMemObject(cl_mem_out);
295
296 // Process the image in the derived class implementation
297 camera->process_image(data->img_meta, voxl::ImageType::CL_MEM, cl_mem_dest);
298 munmap(frame, data->size);
299 }
300
301} // namespace voxl
Base class for camera implementations in VOXL OpenVINS.
volatile int main_running
Main process running flag.
Definition VoxlVars.cpp:38
int en_debug
Enable debug output.
Definition VoxlVars.cpp:149
Global variable declarations and constants for VOXL OpenVINS server.
std::atomic< bool > is_resetting
VIO reset state flag.
std::atomic< uint32_t > vio_error_codes
VIO error codes.
#define PROCESS_NAME
Process name for the VOXL OpenVINS server.
Definition VoxlVars.h:241
Base class for all camera implementations.
Definition CameraBase.h:57
std::mutex mutex_
Mutex for thread-safe operations.
Definition CameraBase.h:163
cl_context ctx_
OpenCL context used if GPU is enabled.
Definition CameraBase.h:166
cam_info camera_info_
Camera configuration information.
Definition CameraBase.h:154
virtual bool connect()
Initialize the camera pipe connection.
static void camera_callback(int ch, camera_image_metadata_t meta, char *frame, void *context)
Common callback function for pipe client.
virtual void disconnect()
Disconnect and clean up resources.
CameraBase(const cam_info &camera_info)
Constructor.
cl_command_queue q_
OpenCL command queue used if GPU is enabled.
Definition CameraBase.h:169
int channel_
Channel used for pipe communication.
Definition CameraBase.h:157
bool is_connected_
Indicates if camera is connected to pipe.
Definition CameraBase.h:160
virtual void process_image(const camera_image_metadata_t &meta, voxl::ImageType img_type, void *frame)=0
Process incoming image data.
Main namespace for VOXL OpenVINS server components.
Camera information and calibration data.
Definition VoxlCommon.h:146
char name[128]
Camera name identifier.
Definition VoxlCommon.h:147
char tracking_name[128]
Name used for tracking operations.
Definition VoxlCommon.h:148