VOXL OpenVINS Server 1.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 Zauberflote
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 // // Close the pipe
159 // pipe_client_close(channel_);
160 is_connected_ = false;
161
162 if (en_debug)
163 {
164 std::cout << "Disconnected camera: " << camera_info_.name << std::endl;
165 }
166 }
167
168 /**
169 * @brief Common callback function for pipe client
170 *
171 * This function receives raw image data from the pipe and dispatches
172 * it to the appropriate processing method. It serves as the entry
173 * point for all camera data processing.
174 *
175 * The callback performs the following operations:
176 * - Enables thread cancellation for proper cleanup
177 * - Validates the camera context pointer
178 * - Checks for global shutdown conditions
179 * - Dispatches to the derived class process_image method
180 *
181 * @param ch Channel number (unused)
182 * @param meta Image metadata containing timestamp and format information
183 * @param frame Pointer to image data buffer
184 * @param context Context pointer (the CameraBase instance)
185 */
186 void CameraBase::camera_callback(int ch, camera_image_metadata_t meta, char *frame, void *context)
187 {
188 // Enable thread cancellation
189 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
190 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
191
192 // Cast the context pointer back to a CameraBase pointer
193 CameraBase *camera = static_cast<CameraBase *>(context);
194
195 // Make sure we have a valid camera instance
196 if (!camera)
197 {
198 std::cerr << "Invalid camera context in callback" << std::endl;
199 vio_error_codes |= ERROR_CODE_CAM_MISSING;
200 return;
201 }
202
203 // Early check for global shutdown flag
204 if (!main_running)
205 {
206 return;
207 }
208
209 // Process the image in the derived class implementation
210 camera->process_image(meta, voxl::ImageType::CV_MAT, frame);
211 }
212
213 void CameraBase::camera_device_buffer_callback(int ch, mpa_ion_buf_t *data, void *context)
214 {
215 // Enable thread cancellation
216 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
217 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
218
219 // Cast the context pointer back to a CameraBase pointer
220 CameraBase *camera = static_cast<CameraBase *>(context);
221
222 // Make sure we have a valid camera instance
223 if (!camera)
224 {
225 std::cerr << "Invalid camera context in callback" << std::endl;
226 vio_error_codes |= ERROR_CODE_CAM_MISSING;
227 return;
228 }
229
230 if (is_resetting.load(std::memory_order_relaxed))
231 return;
232
233 // Early check for global shutdown flag
234 if (!main_running)
235 return;
236
237 auto meta = data->img_meta;
238
239 cl_int err = CL_SUCCESS;
240 if (!camera->ctx_)
241 camera->ctx_ = modal_flow::ocl::OclDevice::Instance().context();
242 if (!camera->q_)
243 camera->q_ = clCreateCommandQueue(camera->ctx_, modal_flow::ocl::OclDevice::Instance().device(), 0, &err);
244 if (err != CL_SUCCESS)
245 {
246 fprintf(stderr, "clCreateCommandQueue err=%d\n", err);
247 return;
248 }
249
250 void *frame = mmap(NULL, data->size, PROT_READ | PROT_WRITE, MAP_SHARED, data->fd, 0);
251 if (frame == MAP_FAILED)
252 {
253 perror("mmap");
254 return;
255 }
256 cl_mem_ion_host_ptr cl_mem_ptr;
257 memset(&cl_mem_ptr, 0, sizeof(cl_mem_ion_host_ptr));
258 cl_mem_ptr.ext_host_ptr.allocation_type = CL_MEM_ION_HOST_PTR_QCOM;
259 cl_mem_ptr.ext_host_ptr.host_cache_policy = CL_MEM_HOST_UNCACHED_QCOM; // CL_MEM_HOST_WRITEBACK_QCOM; //CL_MEM_HOST_UNCACHED_QCOM;
260 cl_mem_ptr.ion_filedesc = data->fd;
261 cl_mem_ptr.ion_hostptr = frame;
262
263 cl_int err_code;
264 cl_mem cl_mem_out = clCreateBuffer(camera->ctx_,
265 CL_MEM_HOST_NO_ACCESS | CL_MEM_USE_HOST_PTR | CL_MEM_EXT_HOST_PTR_QCOM,
266 data->size,
267 &cl_mem_ptr,
268 &err_code);
269
270 if (err_code != CL_SUCCESS)
271 {
272 fprintf(stderr, "Error: clCreateBuffer failed with code %d\n", err_code);
273 }
274
275 cl_mem cl_mem_dest = clCreateBuffer(camera->ctx_,
276 CL_MEM_HOST_NO_ACCESS | CL_MEM_READ_ONLY,
277 data->size,
278 NULL,
279 &err_code);
280 if (err_code != CL_SUCCESS)
281 {
282 fprintf(stderr, "Error: clCreateBuffer failed for destination buffer with code %d\n", err_code);
283 }
284
285 err_code = clEnqueueCopyBuffer(camera->q_,
286 cl_mem_out, // Source buffer (ION-backed memory)
287 cl_mem_dest, // Destination buffer (GPU memory)
288 0, 0, // Source and destination offsets
289 meta.height * meta.width * sizeof(uint8_t), // Size
290 0, nullptr, nullptr);
291 if (err_code != CL_SUCCESS)
292 {
293 fprintf(stderr, "Error: clEnqueueCopyBuffer failed with code %d\n", err_code);
294 }
295 clFinish(camera->q_);
296 clReleaseMemObject(cl_mem_out);
297
298 // Process the image in the derived class implementation
299 camera->process_image(data->img_meta, voxl::ImageType::CL_MEM, cl_mem_dest);
300 munmap(frame, data->size);
301 }
302
303} // 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:148
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:288
Base class for all camera implementations.
Definition CameraBase.h:57
std::mutex mutex_
Mutex for thread-safe operations.
Definition CameraBase.h:164
cl_context ctx_
OpenCL context used if GPU is enabled.
Definition CameraBase.h:167
cam_info camera_info_
Camera configuration information.
Definition CameraBase.h:155
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:170
int channel_
Channel used for pipe communication.
Definition CameraBase.h:158
bool is_connected_
Indicates if camera is connected to pipe.
Definition CameraBase.h:161
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:198
char name[128]
Camera name identifier.
Definition VoxlCommon.h:199
char tracking_name[128]
Name used for tracking operations.
Definition VoxlCommon.h:200