diff --git a/include/libcamera/ipa/raspberrypi.fbs b/include/libcamera/ipa/raspberrypi.fbs
new file mode 100644
index 0000000..15ec84a
--- /dev/null
+++ b/include/libcamera/ipa/raspberrypi.fbs
@@ -0,0 +1,99 @@
+enum RPiConfigParameters:uint16 {
+	NONE = 0,
+	RPI_IPA_CONFIG_LS_TABLE,
+	RPI_IPA_CONFIG_STAGGERED_WRITE,
+	RPI_IPA_CONFIG_SENSOR,
+}
+
+enum RPiEvents:uint16 {
+	NONE = 0,
+	RPI_IPA_EVENT_SIGNAL_STAT_READY,
+	RPI_IPA_EVENT_SIGNAL_ISP_PREPARE,
+	RPI_IPA_EVENT_QUEUE_REQUEST,
+}
+
+enum RPiActions:uint16 {
+	NONE = 0,
+	RPI_IPA_ACTION_V4L2_SET_STAGGERED,
+	RPI_IPA_ACTION_V4L2_SET_ISP,
+	RPI_IPA_ACTION_STATS_METADATA_COMPLETE,
+	RPI_IPA_ACTION_RUN_ISP,
+	RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME,
+	RPI_IPA_ACTION_EMBEDDED_COMPLETE,
+}
+
+// TODO define this for all primitive types, and make global
+table UnsignedInt {
+	value:uint32;
+}
+
+// TODO make this global
+// TODO rename this
+table ControlList {
+	list:[uint8];
+}
+
+// Data containers
+
+table RPiStaggeredWritePayload {
+	gainDelay:uint32;
+	exposureDelay:uint32;
+	sensorMetadata:uint32;
+}
+
+table RPiIspPreparePayload {
+	embeddedbufferId:uint32;
+	bayerbufferId:uint32;
+}
+
+table RPiStatsCompletePayload {
+	bufferId:uint32;
+	controls:ControlList;
+}
+
+
+// Payload unions
+
+union RPiConfigureUnion {
+	lsTableHandle:UnsignedInt,
+	staggeredWriteResult:RPiStaggeredWritePayload,
+	controls:ControlList,
+}
+
+table RPiConfigurePayload {
+        op:RPiConfigParameters;
+	payload:RPiConfigureUnion;
+}
+
+union RPiEventPayload {
+	bufferId:UnsignedInt,
+	ispPrepare:RPiIspPreparePayload,
+	controls:ControlList,
+}
+
+union RPiActionPayload {
+	bufferId:UnsignedInt,
+	statsComplete:RPiStatsCompletePayload,
+	controls:ControlList,
+}
+
+
+// IPA function parameters
+
+table RPiConfigParams {
+	params:[RPiConfigurePayload];
+}
+
+table RPiEventParams {
+	ev:RPiEvents;
+	payload:RPiEventPayload;
+}
+
+table RPiActionParams {
+	op:RPiActions;
+	payload:RPiActionPayload;
+}
+
+root_type RPiConfigureParams;
+root_type RPiEventParams;
+root_type RPiActionParams;
diff --git a/include/libcamera/ipa/raspberrypi.h b/include/libcamera/ipa/raspberrypi.h
index a493776..69b3808 100644
--- a/include/libcamera/ipa/raspberrypi.h
+++ b/include/libcamera/ipa/raspberrypi.h
@@ -10,24 +10,6 @@
 #include <libcamera/control_ids.h>
 #include <libcamera/controls.h>
 
-enum RPiConfigParameters {
-	RPI_IPA_CONFIG_LS_TABLE = (1 << 0),
-	RPI_IPA_CONFIG_STAGGERED_WRITE = (1 << 1),
-	RPI_IPA_CONFIG_SENSOR = (1 << 2),
-};
-
-enum RPiOperations {
-	RPI_IPA_ACTION_V4L2_SET_STAGGERED = 1,
-	RPI_IPA_ACTION_V4L2_SET_ISP,
-	RPI_IPA_ACTION_STATS_METADATA_COMPLETE,
-	RPI_IPA_ACTION_RUN_ISP,
-	RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME,
-	RPI_IPA_ACTION_EMBEDDED_COMPLETE,
-	RPI_IPA_EVENT_SIGNAL_STAT_READY,
-	RPI_IPA_EVENT_SIGNAL_ISP_PREPARE,
-	RPI_IPA_EVENT_QUEUE_REQUEST,
-};
-
 enum RPiIpaMask {
 	ID		= 0x0ffff,
 	STATS		= 0x10000,
diff --git a/include/libcamera/ipa/raspberrypi.libcamera.decl b/include/libcamera/ipa/raspberrypi.libcamera.decl
new file mode 100644
index 0000000..bd8c9c7
--- /dev/null
+++ b/include/libcamera/ipa/raspberrypi.libcamera.decl
@@ -0,0 +1,75 @@
+namespace RPi;
+
+// opcodes
+// these must be enums, and must be named as shown
+
+// required
+// must specify which union option each value corresponds to
+enum ConfigOps {
+	RPI_IPA_CONFIG_LS_TABLE:lsTableHandle,
+	RPI_IPA_CONFIG_STAGGERED_WRITE:staggeredWriteResult,
+	RPI_IPA_CONFIG_SENSOR:controls,
+}
+
+// required
+// must specify which union option each value corresponds to
+enum EventOps {
+	RPI_IPA_EVENT_SIGNAL_STAT_READY:bufferId,
+	RPI_IPA_EVENT_SIGNAL_ISP_PREPARE:ispPrepare,
+	RPI_IPA_EVENT_QUEUE_REQUEST:controls,
+}
+
+// required
+// must specify which union option each value corresponds to
+enum ActionOps {
+	RPI_IPA_ACTION_V4L2_SET_STAGGERED:controls,
+	RPI_IPA_ACTION_V4L2_SET_ISP:controls,
+	RPI_IPA_ACTION_STATS_METADATA_COMPLETE:statsComplete,
+	RPI_IPA_ACTION_RUN_ISP:bufferId,
+	RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME:bufferId,
+	RPI_IPA_ACTION_EMBEDDED_COMPLETE:bufferId,
+}
+
+// Custom Data containers
+
+table RPiStaggeredWritePayload {
+	gainDelay:uint32;
+	exposureDelay:uint32;
+	sensorMetadata:uint32;
+}
+
+table RPiIspPreparePayload {
+	embeddedbufferId:uint32;
+	bayerbufferId:uint32;
+}
+
+table RPiStatsCompletePayload {
+	bufferId:uint32;
+	controls:ControlList;
+}
+
+
+// First level payload unions
+// these must be unions, and must be named as shown
+
+// required
+// this one is actually in a vector of payload objects (op-union pair)
+union ConfigPayload {
+	lsTableHandle:uint32,
+	staggeredWriteResult:RPiStaggeredWritePayload,
+	controls:ControlList,
+}
+
+// required
+union EventPayload {
+	bufferId:uint32,
+	ispPrepare:RPiIspPreparePayload,
+	controls:ControlList,
+}
+
+// required
+union ActionPayload {
+	bufferId:uint32,
+	statsComplete:RPiStatsCompletePayload,
+	controls:ControlList,
+}
diff --git a/include/libcamera/ipa/raspberrypi_wrapper.h b/include/libcamera/ipa/raspberrypi_wrapper.h
new file mode 100644
index 0000000..e5e1a06
--- /dev/null
+++ b/include/libcamera/ipa/raspberrypi_wrapper.h
@@ -0,0 +1,466 @@
+// will be automatically generated by custom compiler
+
+#ifndef __LIBCAMERA_IPA_INTERFACE_RASPBERRYPI_FB_H__
+#define __LIBCAMERA_IPA_INTERFACE_RASPBERRYPI_FB_H__
+
+#include "raspberrypi_generated.h"
+
+namespace libcamera {
+
+// TODO this (and deserialize) should go global
+inline flatbuffers::Offset<ControlList> serializeControlList(flatbuffers::FlatBufferBuilder &builder, ControlList &list)
+{
+	ControlSerializer serializer;
+
+	// TODO need a way to specify the info map
+	size_t size = serializer.binarySize(RPiControls);
+	std::vector<uint8_t> infoData(size);
+	ByteStreamBuffer buffer(infoData.data(), infoData.size());
+	serializer.serialize(RPiControls, buffer);
+
+	size = serializer.binarySize(list);
+	std::vector<uint8_t> listData(size);
+	buffer = ByteStreamBuffer(listData.data(), listData.size());
+	serializer.serialize(list, buffer);
+
+	// don't need to error check; just write empty vector
+	return CreateControlListDirect(builder, listData);
+}
+
+// TODO fix the input type for this (like ControlListFB or something?)
+inline ControlList deserializeControlList(ControlList *obj)
+{
+	ControlSerializer deserializer;
+	std::vector<uint8_t> buf = std::vector(obj->begin(), obj->end());
+
+	std::vector<uint8_t> infoData(size);
+	BytesStreamBuffer buffer(const_cast<const uint8_t *>(infoData.data()), infoData.size());
+	ControlInfoMap infoMap = deserializer.deserialize<ControlInfoMap>(buffer);
+	// TODO what to do for error checking?
+
+	std::vector<uint8_t> listData(size);
+	buffer = ByteStreamBuffer(const_cast<const uint8_t *>(listData.data()), listData.size());
+	ControlList list = deserializer.deserialize<ControlList>(buffer);
+
+	return list;
+}
+
+
+enum RPiConfigParametersWrapper {
+	RPI_IPA_CONFIG_LS_TABLE = 1,
+	RPI_IPA_CONFIG_STAGGERED_WRITE = 2,
+	RPI_IPA_CONFIG_SENSOR = 3,
+};
+
+enum RPiEventsWrapper {
+  RPI_IPA_EVENT_SIGNAL_STAT_READY = 1,
+  RPI_IPA_EVENT_SIGNAL_ISP_PREPARE = 2,
+  RPI_IPA_EVENT_QUEUE_REQUEST = 3,
+};
+
+enum RPiActionsWrapper {
+	RPI_IPA_ACTION_V4L2_SET_STAGGERED,
+	RPI_IPA_ACTION_V4L2_SET_ISP,
+	RPI_IPA_ACTION_STATS_METADATA_COMPLETE,
+	RPI_IPA_ACTION_RUN_ISP,
+	RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME,
+	RPI_IPA_ACTION_EMBEDDED_COMPLETE,
+};
+
+struct RPiStaggeredWritePayloadWrapper : Serializable
+{
+	RPiStaggeredWritePayloadWrapper() {}
+
+	RPiStaggeredWritePayloadWrapper(uint32_t gainDelay, uint32_t exposureDelay, uint32_t sensorMetadata) : gainDelay_(gainDelay), exposureDelay_(exposureDelay), sensorMetadata_(sensorMetadata) {}
+
+	RPiStaggeredWritePayloadWrapper(const RPiStaggeredWritePayload *buf)
+	{
+		const RPiStaggeredWritePayload *obj = flatbuffers::GetRoot<RPiStaggeredWritePayload>(buf);
+
+		gainDelay_ = obj->gainDelay();
+		exposureDelay_ = obj->exposureDelay();
+		sensorMetadata_ = obj->sensorMetadata();
+	}
+
+	flatbuffers::Offset<RPiStaggeredWritePayload> serialize(flatbuffers::FlatBufferBuilder &builder)
+	{
+		// - construct compound children depth-first
+		// - get simple data
+		// - feed to Create
+
+		// nop for gainDelay_
+
+		// nop for exposureDelay_
+
+		// nop for sensorMetadata_
+
+		return CreateRPiStaggeredWritePayload(builder, gainDelay_, exposureDelay_, sensorMetadata_);
+	}
+
+	uint32_t gainDelay_;
+	uint32_t exposureDelay_;
+	uint32_t sensorMetadata_;
+}
+
+struct RPiIspPreparePayloadWrapper : Serializable
+{
+	RPiIspPreparePayloadWrapper() {}
+
+	RPiIspPreparePayloadWrapper(uint32_t embeddedbufferId, uint32_t bayerbufferId) : embeddedbufferId_(embeddedbufferId), bayerbufferId_(bayerbufferId) {}
+
+	RPiIspPreparePayloadWrapper(const RPiIspPreparePayload *buf)
+	{
+		const RPiIspPreparePayload *obj = flatbuffers::GetRoot<RPiIspPreparePayload>(buf);
+
+		embeddedbufferId_ = obj->embeddedbufferId();
+		bayerbufferId_ = obj->bayerbufferId();
+	}
+
+	flatbuffers::Offset<RPiIspPreparePayload> serialize(flatbuffers::FlatBufferBuilder &builder)
+	{
+		// - construct compound children depth-first
+		// - get simple data
+		// - feed to Create
+
+		// nop for embeddedbufferId_
+
+		// nop for bayerbufferId_
+
+		return CreateRPiIspPreparePayload(builder, embeddedbufferId_, bayerbufferId_);
+	}
+
+	uint32_t embeddedbufferId_;
+	uint32_t bayerbufferId_;
+}
+
+struct RPiStatsCompletePayloadWrapper : Serializable
+{
+	RPiStatsCompletePayloadWrapper() {}
+
+	RPiStatsCompletePayloadWrapper(uint32_t bufferId, ControlList &controls) : bufferId_(bufferId), controls_(controls) {}
+
+	// deserialize
+	RPiStatsCompletePayloadWrapper(const RPiStatsCompletePayload *buf)
+	{
+		const RPiStatsCompletePayload *obj = flatbuffers::GetRoot<RPiStatsCompletePayload>(buf);
+
+		bufferId_ = obj->bufferId();
+		controls_ = deserializeControlList(obj->controls());
+	}
+
+	flatbuffers::Offset<RPiStatsCompletePayloadWrapper> serialize(flatbuffers::FlatBufferBuilder &builder)
+	{
+		// - construct compound children depth-first
+		// - get simple data
+		// - feed to Create
+
+		// nop for bufferId_
+
+		// serialize controls_
+		flatbuffers::Offset<ControlList> controls = serializeControlList(builder, controls_);
+
+		return CreateRPiStatsCompletePayload(builder, bufferId_, controls);
+	}
+
+	uint32_t bufferId_;
+	ControlList controls_;
+}
+
+union RPiConfigureUnionWrapper
+{
+	uint32_t lsTableHandle_;
+	RPiStaggeredWritePayload staggeredWriteResult_;
+	ControlList contols_;
+}
+
+struct RPiConfigurePayloadWrapper : Serializable
+{
+	RPiConfigurePayloadWrapper() {}
+
+	RPiConfigurePayloadWrapper(enum RPiConfigParametersWrapper op, RPiConfigureUnionWrapper payload) : op_(op), payload_(payload) {}
+
+	// deserialize
+	RPiConfigurePayloadWrapper(const RPiConfigurePayload *buf)
+	{
+		// yeah fill this in if you want
+	}
+
+	// deserialize
+	// TODO need this if is a member of vector
+	RPiConfigurePayloadWrapper(flatbuffers::Offset<RPiConfigurePayload> &p)
+	{
+		// nop for op
+		op_ = p.op();
+
+		// start of union block for payload_
+		switch (op_) {
+		case RPI_IPA_CONFIG_LS_TABLE:
+			payload_.lsTableHandle_ = p.payload_as_lsTableHandle();
+			break;
+		case RPI_IPA_CONFIG_STAGGERED_WRITE:
+			payload_.staggeredWriteResult_ = RPiStaggeredWritePayloadWrapper(p.payload_as_staggeredWriteResult);
+			break;
+		case RPI_IPA_CONFIG_SENSOR:
+			payload_.controls_ = deserializeControlList(p.payload_as_controls());
+			break;
+		}
+		// end of union block for payload_
+	}
+
+	flatbuffers::Offset<RPiConfigurePayload> serialize(flatbuffers::FlatBufferBuilder &builder)
+	{
+		// - construct compound children depth-first
+		// - get simple data
+		// - feed to Create
+
+		// nop for op_
+		RPiConfigureUnion payloadType;
+		flatbuffers::Offset<void> payload;
+
+		// start of union block for payload_
+		switch (op_) {
+		case RPI_IPA_CONFIG_LS_TABLE:
+			payloadType = RPiConfigureUnion_lsTableHandle;
+			payload = CreateUnsignedInt(builder, payload_.lsTableHandle_);
+			break;
+		case RPI_IPA_CONFIG_STAGGERED_WRITE:
+			payloadType = RPiConfigureUnion_staggeredWriteResult;
+			payload = payload_.staggeredWriteResult_.serialize(builder);
+			break;
+		case RPI_IPA_CONFIG_SENSOR:
+			// controls
+			payloadType = RPiConfigureUnion_controls;
+			payload = serializeControlList(builder, payload_.controls_);
+			break;
+		}
+		// end of union block for payload_
+
+		return CreateRPiConfigurePayload(builder, op_, payloadType, payload);
+	}
+
+	enum RPiConfigParametersWrapper op_;
+	RPiConfigureUnionWrapper payload_;
+}
+
+union RPiEventPayloadWrapper
+{
+	uint32_t bufferId_;
+	RPiIspPreparePayloadWrapper ispPrepare_;
+	ControlList controls_;
+}
+
+union RPiActionPayloadWrapper
+{
+	uint32_t bufferId_;
+	RPiStatsCompletePayloadWrapper statsComplete_;
+	ControlList controls_;
+}
+
+struct RPiConfigureParamsWrapper : Serializable
+{
+	RPiConfigureParamsWrapper() {}
+
+	RPiConfigureParamsWrapper(std::vector<RPiConfigurePayloadWrapper> payload) : payload_(payload) {}
+
+	// deserialize
+	RPiConfigureParamsWrapper(const uint8_t *buf)
+	{
+		const RPiConfigureParams *obj = flatbuffers::GetRoot<RPiConfigureParams>(buf);
+
+		// start of vector block for payload_
+		flatbuffers::Vector<flatbuffers::Offset<RPiConfigurePayload>> *payload = obj->params();
+		std::transform(payload->begin(), payload->end(), std::back_inserter(payload_),
+				[](flatbuffers::Offset<RPiConfigurePayload> &p) -> RPiConfigurePayloadWrapper {
+					return RPiConfigurePayloadWrapper(p);
+				});
+		// end of vector block for payload_
+	}
+
+	flatbuffers::Offset<RPiConfigureParams> serialize(flatbuffers::FlatBufferBuilder &builder)
+	{
+		// - construct compound children depth-first
+		// - get simple data
+		// - feed to Create
+
+		// start of vector block for payload_
+		std::vector<flatbuffers::Offset<RPiConfigurePayload>> payload;
+		std::transform(payload_.begin(), payload_.end(), std::back_inserter(payload),
+				[](RPiConfigurePayloadWrapper &p) -> flatbuffers::Offset<RPiConfigurePayload> { return p.serialize(builder); });
+		// end of vector block for payload_
+
+		// use direct if there's vector as a member
+		return CreateRPiConfigureParamsDirect(builder, payload);
+	}
+
+	// this is only for root_type
+	std::pair<uint8_t *, size_t> serialize()
+	{
+		flatbuffers::FlatBufferBuilder builder(1024);
+		builder.Finish(this.serialize(builder));
+
+		uint8_t *buf = builder.GetBufferPointer();
+		size_t size = builder.GetSize();
+		return {buf, size};
+	}
+
+	std::vector<RPiConfigurePayloadWrapper> payload_;
+}
+
+struct RPiEventParamsWrapper : Serializable
+{
+	RPiEventParamsWrapper() {}
+
+	RPiEventParamsWrapper(enum RPiEventsWrapper ev, RPiEventPayloadWrapper payload) : ev_(ev), payload_(payload) {}
+
+	// deserialize
+	RPiEventParamsWrapper(const uint8_t *buf)
+	{
+		const RPiEventParams *obj = flatbuffers::GetRoot<RPiEventParams>(buf);
+
+		ev_ = obj->ev();
+
+		// start of union block for payload_
+		switch (ev_) {
+		case RPI_IPA_EVENT_SIGNAL_STAT_READY:
+			payload_.bufferId_ = obj->payload_as_bufferId()->value();
+			break;
+		case RPI_IPA_EVENT_SIGNAL_ISP_PREPARE:
+			payload_.ispPrepare_ = RPiIspPreparePayloadWrapper(obj->payload_as_ispPrepare());
+			break;
+		case RPI_IPA_EVENT_QUEUE_REQUEST:
+			payload_.controls_ = deserializeControlList(obj->payload_as_controls());
+			break;
+		}
+		// end of union block for payload_
+	}
+
+	flatbuffers::Offset<RPiEventParams> serialize(flatbuffers::FlatBufferBuilder &builder)
+	{
+		// - construct compound children depth-first
+		// - get simple data
+		// - feed to Create
+
+		// nop for ev_
+
+		// start of union block for payload_
+		RPiEventPayload payloadType;
+		flatbuffers::Offset<void> payload;
+
+		switch (ev_) {
+		case RPI_IPA_EVENT_SIGNAL_STAT_READY:
+			payloadType = RPiEventPayload_bufferId;
+			payload = CreateUnsignedInt(builder, payload_.bufferId_);
+			break;
+		case RPI_IPA_EVENT_SIGNAL_ISP_PREPARE:
+			payloadType = RPiEventPayload_ispPrepare;
+			payload = payload_.ispPrepare_.serialize(builder);
+			break;
+		case RPI_IPA_EVENT_QUEUE_REQUEST:
+			payloadType = RPiEventPayload_controls;
+			payload = serializeControlList(builder, payload_.controls_);
+			break;
+		}
+		// end of union block
+
+		return CreateRPiEventParams(builder, ev_, payloadType, payload);
+	}
+
+	// this is only for root_type
+	std::pair<uint8_t *, size_t> serialize()
+	{
+		flatbuffers::FlatBufferBuilder builder(1024);
+		builder.Finish(this.serialize(builder));
+
+		uint8_t *buf = builder.GetBufferPointer();
+		size_t size = builder.GetSize();
+		return {buf, size};
+	}
+
+	enum RPiEventsWrapper ev_;
+	RPiEventPayloadWrapper payload_;
+}
+
+struct RPiActionParamsWrapper : Serializable
+{
+	RPiActionParamsWrapper() {}
+
+	RPiActionParamsWrapper(enum RPiActionsWrapper op, RPiActionPayloadWrapper payload) : op_(op), payload_(payload) {}
+
+	// deserialize
+	RPiActionParamsWrapper(const uint8_t *buf)
+	{
+		const RPiActionParams *obj = flatbuffers::GetRoot<RPiActionParams>(buf);
+
+		op_ = obj->op();
+
+		// start of union block for payload_
+		switch (op_) {
+		case RPI_IPA_ACTION_V4L2_SET_STAGGERED:
+		case RPI_IPA_ACTION_V4L2_SET_ISP:
+			payload_.controls_ = deserializeControlList(obj->payload_as_controls());
+			break;
+		case RPI_IPA_ACTION_STATS_METADATA_COMPLETE:
+			payload_.statsComplete_ = RPiStatsCompletePayloadWrapper(obj->payload_as_statsComplete());
+			break;
+		case RPI_IPA_ACTION_RUN_ISP:
+		case RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME:
+		case RPI_IPA_ACTION_EMBEDDED_COMPLETE:
+			// UnsignedInt needs ->value()
+			payload_.bufferId_ = obj->payload_as_bufferId()->value();
+			break;
+		}
+		// end of union block for payload_
+	}
+
+	flatbuffers::Offset<RPiEventParams> serialize(flatbuffers::FlatBufferBuilder &builder)
+	{
+		// - construct compound children depth-first
+		// - get simple data
+		// - feed to Create
+
+		// nop for op_
+
+		// start of union block for payload_
+		RPiActionPayload payloadType;
+		flatbuffers::Offset<void> payload;
+
+		switch (op_) {
+		case RPI_IPA_ACTION_V4L2_SET_STAGGERED:
+		case RPI_IPA_ACTION_V4L2_SET_ISP:
+			payloadType = RPiActionPayload_controls;
+			payload = serializeControlList(builder, payload_.controls_);
+			break;
+		case RPI_IPA_ACTION_STATS_METADATA_COMPLETE:
+			payloadType = RPiActionPayload_statsComplete;
+			payload = payload_.statsComplete_.serialize(builder);
+			break;
+		case RPI_IPA_ACTION_RUN_ISP:
+		case RPI_IPA_ACTION_RUN_ISP_AND_DROP_FRAME:
+		case RPI_IPA_ACTION_EMBEDDED_COMPLETE:
+			payloadType = RPiActionPayload_bufferId;
+			payload = CreateUnsignedInt(builder, payload_.bufferId_);
+			break;
+		}
+		// end of union block for payload_
+
+		return CreateRPiActionParams(builder, op_, payloadType, payload);
+	}
+
+	// this is only for root_type
+	std::pair<uint8_t *, size_t> serialize()
+	{
+		flatbuffers::FlatBufferBuilder builder(1024);
+		builder.Finish(this.serialize(builder));
+
+		uint8_t *buf = builder.GetBufferPointer();
+		size_t size = builder.GetSize();
+		return {buf, size};
+	}
+
+	enum RPiActionsWrapper op_;
+	RPiActionPayloadWrapper payload_;
+}
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPA_INTERFACE_RASPBERRYPI_FB_H__ */
