Commit: 004752ed6527fcbbec1a09443e69c35aa71c9f23
Parent: e06bc2e345da76ce0c8ca5b1723a8ff76710e5f4
Author: Randy Palamar
Date: Tue, 9 Jul 2024 14:01:35 -0600
modify helper to be a callable lib
This also adds a shared memory region for sending imaging
parameters in from an external process.
Diffstat:
7 files changed, 225 insertions(+), 135 deletions(-)
diff --git a/beamformer.h b/beamformer.h
@@ -48,18 +48,6 @@ enum program_flags {
RELOAD_SHADERS = 1 << 0,
};
-#if defined(__unix__)
- #define GL_GLEXT_PROTOTYPES 1
- #include <GL/glcorearb.h>
- #include <GL/glext.h>
- #include "os_unix.c"
-#elif defined(_WIN32)
- #include <glad.h>
- #include "os_win32.c"
-#else
- #error Unsupported Platform!
-#endif
-
typedef struct {
u32 programs[CS_LAST];
@@ -84,6 +72,28 @@ typedef struct {
} FragmentShaderCtx;
typedef struct {
+ i16 channel_row_mapping[128];
+ i16 channel_column_mapping[128];
+ i16 uforces_channels[128];
+ u32 channel_data_stride;
+ f32 speed_of_sound;
+ f32 sampling_frequency;
+ uv3 output_points;
+} BeamformerParameters;
+
+#if defined(__unix__)
+ #define GL_GLEXT_PROTOTYPES 1
+ #include <GL/glcorearb.h>
+ #include <GL/glext.h>
+ #include "os_unix.c"
+#elif defined(_WIN32)
+ #include <glad.h>
+ #include "os_win32.c"
+#else
+ #error Unsupported Platform!
+#endif
+
+typedef struct {
uv2 window_size;
u32 flags;
@@ -101,6 +111,8 @@ typedef struct {
os_pipe data_pipe;
u32 partial_transfer_count;
+
+ BeamformerParameters *params;
} BeamformerCtx;
#endif /*_BEAMFORMER_H_ */
diff --git a/build.sh b/build.sh
@@ -20,5 +20,4 @@ case "$1" in
;;
esac
-
cc $cflags -o ogl main.c $ldflags
diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c
@@ -0,0 +1,131 @@
+#include "ogl_beamformer_lib.h"
+
+#if defined(__unix__)
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define OS_INVALID_FILE (-1)
+typedef i32 os_file;
+typedef struct {
+ os_file file;
+ char *name;
+} os_pipe;
+#elif defined(_WIN32)
+#include <windows.h>
+
+#define OS_INVALID_FILE (INVALID_HANDLE_VALUE)
+typedef HANDLE os_file;
+typedef struct {
+ os_file file;
+ char *name;
+} os_pipe;
+
+#else
+#error Unsupported Platform
+#endif
+
+static BeamformerParameters *bp;
+static char *shm_name = "/ogl_beamformer_parameters";
+static os_pipe g_pipe = {.file = OS_INVALID_FILE};
+
+#if defined(__unix__)
+static os_pipe
+os_open_named_pipe(char *name)
+{
+ return (os_pipe){.file = open(name, O_WRONLY), .name = name};
+}
+
+static size
+os_write_to_pipe(os_pipe p, void *data, size len)
+{
+ size written = 0, w = 0;
+ do {
+ written += w;
+ w = write(p.file, data, len);
+ } while(written != len && w != 0);
+ return written;
+}
+
+static void
+os_close_pipe(void)
+{
+ close(g_pipe.file);
+}
+
+static BeamformerParameters *
+os_open_shared_memory_area(char *name)
+{
+ i32 fd = shm_open(name, O_RDWR, S_IRUSR|S_IWUSR);
+ if (fd == -1)
+ return NULL;
+
+ BeamformerParameters *new;
+ new = mmap(NULL, sizeof(BeamformerParameters), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ close(fd);
+
+ if (new == MAP_FAILED)
+ return NULL;
+
+ return new;
+}
+
+#elif defined(_WIN32)
+
+static os_pipe
+os_open_named_pipe(char *name)
+{
+ HANDLE pipe = CreateFileA(name, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
+ return (os_pipe){.file = pipe, .name = name};
+}
+
+static size
+os_write_to_pipe(os_pipe p, void *data, size len)
+{
+ DWORD bytes_written;
+ WriteFile(p.file, data, len, &bytes_written, 0);
+ return bytes_written;
+}
+
+static void
+os_close_pipe(void)
+{
+ CloseHandle(g_pipe.file);
+}
+#endif
+
+void
+send_data(char *pipe_name, i16 *data, uv3 data_dim)
+{
+ if (g_pipe.file == OS_INVALID_FILE) {
+ g_pipe = os_open_named_pipe(pipe_name);
+ if (g_pipe.file == OS_INVALID_FILE) {
+ mexErrMsgIdAndTxt("ogl_beamformer:pipe_error", "failed to open pipe");
+ return;
+ }
+ }
+
+ size data_size = data_dim.x * data_dim.y * data_dim.z * sizeof(i16);
+ size written = os_write_to_pipe(g_pipe, data, data_size);
+ if (written != data_size)
+ mexWarnMsgIdAndTxt("ogl_beamformer:write_error",
+ "failed to write full data to pipe: wrote: %ld", written);
+}
+
+void
+set_beamformer_parameters(BeamformerParameters *new_bp)
+{
+ if (bp == NULL) {
+ bp = os_open_shared_memory_area(shm_name);
+ if (bp == NULL) {
+ mexErrMsgIdAndTxt("ogl_beamformer:shared_memory",
+ "failed to open shared memory area");
+ return;
+ }
+ }
+
+ u8 *src = (u8 *)new_bp, *dest = (u8 *)bp;
+ for (size i = 0; i < sizeof(BeamformerParameters); i++)
+ dest[i] = src[i];
+}
diff --git a/helpers/ogl_beamformer_lib.h b/helpers/ogl_beamformer_lib.h
@@ -0,0 +1,36 @@
+/* NOTE: mex.h can still be used to get access to functions that print to the matlab console */
+#include <mex.h>
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef uint8_t u8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef uint32_t u32;
+typedef uint32_t b32;
+typedef float f32;
+typedef double f64;
+typedef ptrdiff_t size;
+
+#if defined(_WIN32)
+#define LIB_FN __declspec(dllexport)
+#else
+#define LIB_FN
+#endif
+
+typedef struct { u32 x, y, z; } uv3;
+typedef struct { f32 x, y, z; } v3;
+
+typedef struct {
+ i16 channel_row_mapping[128];
+ i16 channel_column_mapping[128];
+ i16 uforces_channels[128];
+ u32 channel_data_stride;
+ f32 speed_of_sound;
+ f32 sampling_frequency;
+ uv3 output_points;
+} BeamformerParameters;
+
+LIB_FN void set_beamformer_parameters(BeamformerParameters *);
+LIB_FN void send_data(char *, i16 *, uv3 data_dim);
diff --git a/helpers/ogl_beamformer_pipe.c b/helpers/ogl_beamformer_pipe.c
@@ -1,122 +0,0 @@
-#include <mex.h>
-
-#include <stddef.h>
-#include <stdint.h>
-typedef int16_t i16;
-typedef int32_t i32;
-typedef ptrdiff_t size;
-
-#if defined(__unix__)
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#define OS_INVALID_FILE (-1)
-typedef i32 os_file;
-typedef struct {
- os_file file;
- char *name;
-} os_pipe;
-#elif defined(_WIN32)
-#include <windows.h>
-
-#define OS_INVALID_FILE (INVALID_HANDLE_VALUE)
-typedef HANDLE os_file;
-typedef struct {
- os_file file;
- char *name;
-} os_pipe;
-
-#else
-#error Unsupported Platform
-#endif
-
-/* NOTE: the mexAtExit function is poorly designed and doesn't
- * take a context pointer so this must be a global */
-static os_pipe g_pipe = {.file = OS_INVALID_FILE};
-
-#if defined(__unix__)
-static os_pipe
-os_open_named_pipe(char *name)
-{
- return (os_pipe){.file = open(name, O_WRONLY), .name = name};
-}
-
-static size
-os_write_to_pipe(os_pipe p, void *data, size len)
-{
- size written = 0, w = 0;
- do {
- written += w;
- w = write(p.file, data, len);
- } while(written != len && w != 0);
- return written;
-}
-
-static void
-os_close_pipe(void)
-{
- close(g_pipe.file);
- mxFree(g_pipe.name);
-}
-
-#elif defined(_WIN32)
-
-static os_pipe
-os_open_named_pipe(char *name)
-{
- HANDLE pipe = CreateFileA(name, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
- return (os_pipe){.file = pipe, .name = name};
-}
-
-static size
-os_write_to_pipe(os_pipe p, void *data, size len)
-{
- DWORD bytes_written;
- WriteFile(p.file, data, len, &bytes_written, 0);
- return bytes_written;
-}
-
-static void
-os_close_pipe(void)
-{
- CloseHandle(g_pipe.file);
- mxFree(g_pipe.name);
-}
-#endif
-
-/* NOTE: usage: pipe_data_to_beamformer(pipe_name, data) */
-void
-mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
-{
- if (nrhs != 2) {
- mexErrMsgIdAndTxt("ogl_beamformer:wrong_input",
- "usage: ogl_beamformer_pipe(pipe_name, data)");
- return;
- }
-
- if (g_pipe.file == OS_INVALID_FILE) {
- char *pipe_name = mxArrayToString(prhs[0]);
- g_pipe = os_open_named_pipe(pipe_name);
- if (g_pipe.file == OS_INVALID_FILE) {
- mexErrMsgIdAndTxt("ogl_beamformer:pipe_error", "failed to open pipe");
- mxFree(pipe_name);
- return;
- }
- mexAtExit(os_close_pipe);
- }
-
- const mxArray *mxdata = prhs[1];
- if (!mxIsInt16(mxdata)) {
- mexErrMsgIdAndTxt("ogl_beamformer:invalid_type",
- "invalid data type; only int16 is supported");
- return;
- }
-
- void *data = mxGetPr(mxdata);
- size data_size = mxGetNumberOfElements(mxdata) * sizeof(i16);
- size written = os_write_to_pipe(g_pipe, data, data_size);
- if (written != data_size)
- mexWarnMsgIdAndTxt("ogl_beamformer:write_error",
- "failed to write full data to pipe: wrote: %ld", written);
-}
diff --git a/main.c b/main.c
@@ -213,8 +213,10 @@ main(void)
init_fragment_shader_ctx(&ctx.fsctx, ctx.out_data_dim);
ctx.data_pipe = os_open_named_pipe("/tmp/beamformer_data_fifo");
+ ctx.params = os_open_shared_memory_area("/ogl_beamformer_parameters");
/* TODO: properly handle this? */
ASSERT(ctx.data_pipe.file != OS_INVALID_FILE);
+ ASSERT(ctx.params);
ctx.flags |= RELOAD_SHADERS;
@@ -229,6 +231,10 @@ main(void)
do_beamformer(&ctx, temp_memory);
}
+ /* NOTE: make sure this will get cleaned up after external
+ * programs release their references */
+ os_remove_shared_memory("/ogl_beamformer_parameters");
+
/* NOTE: garbage code needed for Linux */
os_close_named_pipe(ctx.data_pipe);
}
diff --git a/os_unix.c b/os_unix.c
@@ -101,3 +101,31 @@ os_read_pipe_data(os_pipe p, void *buf, size len)
} while (r);
return total_read;
}
+
+static BeamformerParameters *
+os_open_shared_memory_area(char *name)
+{
+ i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
+ if (fd == -1)
+ return NULL;
+
+ if (ftruncate(fd, sizeof(BeamformerParameters)) == -1) {
+ close(fd);
+ return NULL;
+ }
+
+ BeamformerParameters *new;
+ new = mmap(NULL, sizeof(BeamformerParameters), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ close(fd);
+
+ if (new == MAP_FAILED)
+ return NULL;
+
+ return new;
+}
+
+static void
+os_remove_shared_memory(char *name)
+{
+ shm_unlink(name);
+}