Program Listing for File frame.h

Return to documentation for file (include/libcaer/events/frame.h)

#ifndef LIBCAER_EVENTS_FRAME_H_
#define LIBCAER_EVENTS_FRAME_H_

#include "common.h"

#ifdef __cplusplus
extern "C" {
#endif

#define FRAME_COLOR_CHANNELS_SHIFT 1
#define FRAME_COLOR_CHANNELS_MASK  0x00000007
#define FRAME_COLOR_FILTER_SHIFT   4
#define FRAME_COLOR_FILTER_MASK    0x0000000F
#define FRAME_ROI_IDENTIFIER_SHIFT 8
#define FRAME_ROI_IDENTIFIER_MASK  0x0000007F

enum caer_frame_event_color_channels {
    GRAYSCALE = 1,
    RGB       = 3,
    RGBA      = 4,
};

enum caer_frame_event_color_filter {
    MONO = 0,
    RGBG = 1,
    GRGB = 2,
    GBGR = 3,
    BGRG = 4,
    RGBW = 5,
    GRWB = 6,
    WBGR = 7,
    BWRG = 8,
};

PACKED_STRUCT(struct caer_frame_event {
    uint32_t info;
    int32_t ts_startframe;
    int32_t ts_endframe;
    int32_t ts_startexposure;
    int32_t ts_endexposure;
    int32_t lengthX;
    int32_t lengthY;
    int32_t positionX;
    int32_t positionY;
    uint16_t pixels[1]; // size 1 here for C++ compatibility.
});

typedef struct caer_frame_event *caerFrameEvent;
typedef const struct caer_frame_event *caerFrameEventConst;

PACKED_STRUCT(struct caer_frame_event_packet {
    struct caer_event_packet_header packetHeader;
});

typedef struct caer_frame_event_packet *caerFrameEventPacket;
typedef const struct caer_frame_event_packet *caerFrameEventPacketConst;

static inline caerFrameEventPacket caerFrameEventPacketAllocateNumPixels(
    int32_t eventCapacity, int16_t eventSource, int32_t tsOverflow, int32_t maxNumPixels, int16_t maxChannelNumber) {
    if ((maxNumPixels <= 0) || (maxChannelNumber <= 0)) {
        return (NULL);
    }

    size_t pixelSize = sizeof(uint16_t) * (size_t) maxNumPixels * (size_t) maxChannelNumber;
    // '- sizeof(uint16_t)' to compensate for pixels[1] at end of struct for C++ compatibility.
    size_t eventSize = (sizeof(struct caer_frame_event) - sizeof(uint16_t)) + pixelSize;

    return ((caerFrameEventPacket) caerEventPacketAllocate(eventCapacity, eventSource, tsOverflow, FRAME_EVENT,
        I32T(eventSize), offsetof(struct caer_frame_event, ts_endframe)));
}

static inline caerFrameEventPacket caerFrameEventPacketAllocate(int32_t eventCapacity, int16_t eventSource,
    int32_t tsOverflow, int32_t maxLengthX, int32_t maxLengthY, int16_t maxChannelNumber) {
    if ((maxLengthX <= 0) || (maxLengthY <= 0) || (maxChannelNumber <= 0)) {
        return (NULL);
    }

    return (caerFrameEventPacketAllocateNumPixels(
        eventCapacity, eventSource, tsOverflow, maxLengthX * maxLengthY, maxChannelNumber));
}

static inline caerFrameEventPacket caerFrameEventPacketFromPacketHeader(caerEventPacketHeader header) {
    if (caerEventPacketHeaderGetEventType(header) != FRAME_EVENT) {
        return (NULL);
    }

    return ((caerFrameEventPacket) header);
}

static inline caerFrameEventPacketConst caerFrameEventPacketFromPacketHeaderConst(caerEventPacketHeaderConst header) {
    if (caerEventPacketHeaderGetEventType(header) != FRAME_EVENT) {
        return (NULL);
    }

    return ((caerFrameEventPacketConst) header);
}

static inline caerFrameEvent caerFrameEventPacketGetEvent(caerFrameEventPacket packet, int32_t n) {
    // Check that we're not out of bounds.
    if (n < 0 || n >= caerEventPacketHeaderGetEventCapacity(&packet->packetHeader)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventPacketGetEvent() with invalid event offset %" PRIi32
            ", while maximum allowed value is %" PRIi32 ".",
            n, caerEventPacketHeaderGetEventCapacity(&packet->packetHeader) - 1);
        return (NULL);
    }

    // Return a pointer to the specified event.
    return ((caerFrameEvent) (((uint8_t *) &packet->packetHeader)
                              + (CAER_EVENT_PACKET_HEADER_SIZE
                                  + U64T(n * caerEventPacketHeaderGetEventSize(&packet->packetHeader)))));
}

static inline caerFrameEventConst caerFrameEventPacketGetEventConst(caerFrameEventPacketConst packet, int32_t n) {
    // Check that we're not out of bounds.
    if (n < 0 || n >= caerEventPacketHeaderGetEventCapacity(&packet->packetHeader)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventPacketGetEventConst() with invalid event offset %" PRIi32
            ", while maximum allowed value is %" PRIi32 ".",
            n, caerEventPacketHeaderGetEventCapacity(&packet->packetHeader) - 1);
        return (NULL);
    }

    // Return a pointer to the specified event.
    return ((caerFrameEventConst) (((const uint8_t *) &packet->packetHeader)
                                   + (CAER_EVENT_PACKET_HEADER_SIZE
                                       + U64T(n * caerEventPacketHeaderGetEventSize(&packet->packetHeader)))));
}

static inline int32_t caerFrameEventGetTSStartOfFrame(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->ts_startframe))));
}

static inline int64_t caerFrameEventGetTSStartOfFrame64(caerFrameEventConst event, caerFrameEventPacketConst packet) {
    // Even if frames have multiple time-stamps, it's not possible for later time-stamps to
    // be in a different TSOverflow period, since in those rare cases the event is dropped.
    return (I64T((U64T(caerEventPacketHeaderGetEventTSOverflow(&packet->packetHeader)) << TS_OVERFLOW_SHIFT)
                 | U64T(caerFrameEventGetTSStartOfFrame(event))));
}

static inline void caerFrameEventSetTSStartOfFrame(caerFrameEvent event, int32_t startFrame) {
    if (startFrame < 0) {
        // Negative means using the 31st bit!
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event", "Called caerFrameEventSetTSStartOfFrame() with negative value!");
        return;
    }

    event->ts_startframe = I32T(htole32(U32T(startFrame)));
}

static inline int32_t caerFrameEventGetTSEndOfFrame(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->ts_endframe))));
}

static inline int64_t caerFrameEventGetTSEndOfFrame64(caerFrameEventConst event, caerFrameEventPacketConst packet) {
    // Even if frames have multiple time-stamps, it's not possible for later time-stamps to
    // be in a different TSOverflow period, since in those rare cases the event is dropped.
    return (I64T((U64T(caerEventPacketHeaderGetEventTSOverflow(&packet->packetHeader)) << TS_OVERFLOW_SHIFT)
                 | U64T(caerFrameEventGetTSEndOfFrame(event))));
}

static inline void caerFrameEventSetTSEndOfFrame(caerFrameEvent event, int32_t endFrame) {
    if (endFrame < 0) {
        // Negative means using the 31st bit!
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event", "Called caerFrameEventSetTSEndOfFrame() with negative value!");
        return;
    }

    event->ts_endframe = I32T(htole32(U32T(endFrame)));
}

static inline int32_t caerFrameEventGetTSStartOfExposure(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->ts_startexposure))));
}

static inline int64_t caerFrameEventGetTSStartOfExposure64(
    caerFrameEventConst event, caerFrameEventPacketConst packet) {
    // Even if frames have multiple time-stamps, it's not possible for later time-stamps to
    // be in a different TSOverflow period, since in those rare cases the event is dropped.
    return (I64T((U64T(caerEventPacketHeaderGetEventTSOverflow(&packet->packetHeader)) << TS_OVERFLOW_SHIFT)
                 | U64T(caerFrameEventGetTSStartOfExposure(event))));
}

static inline void caerFrameEventSetTSStartOfExposure(caerFrameEvent event, int32_t startExposure) {
    if (startExposure < 0) {
        // Negative means using the 31st bit!
        caerLogEHO(
            CAER_LOG_CRITICAL, "Frame Event", "Called caerFrameEventSetTSStartOfExposure() with negative value!");
        return;
    }

    event->ts_startexposure = I32T(htole32(U32T(startExposure)));
}

static inline int32_t caerFrameEventGetTSEndOfExposure(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->ts_endexposure))));
}

static inline int64_t caerFrameEventGetTSEndOfExposure64(caerFrameEventConst event, caerFrameEventPacketConst packet) {
    // Even if frames have multiple time-stamps, it's not possible for later time-stamps to
    // be in a different TSOverflow period, since in those rare cases the event is dropped.
    return (I64T((U64T(caerEventPacketHeaderGetEventTSOverflow(&packet->packetHeader)) << TS_OVERFLOW_SHIFT)
                 | U64T(caerFrameEventGetTSEndOfExposure(event))));
}

static inline void caerFrameEventSetTSEndOfExposure(caerFrameEvent event, int32_t endExposure) {
    if (endExposure < 0) {
        // Negative means using the 31st bit!
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event", "Called caerFrameEventSetTSEndOfExposure() with negative value!");
        return;
    }

    event->ts_endexposure = I32T(htole32(U32T(endExposure)));
}

static inline int32_t caerFrameEventGetExposureLength(caerFrameEventConst event) {
    return (caerFrameEventGetTSEndOfExposure(event) - caerFrameEventGetTSStartOfExposure(event));
}

static inline int32_t caerFrameEventGetTimestamp(caerFrameEventConst event) {
    return (caerFrameEventGetTSStartOfExposure(event) + (caerFrameEventGetExposureLength(event) / 2));
}

static inline int64_t caerFrameEventGetTimestamp64(caerFrameEventConst event, caerFrameEventPacketConst packet) {
    // Even if frames have multiple time-stamps, it's not possible for later time-stamps to
    // be in a different TSOverflow period, since in those rare cases the event is dropped.
    return (caerFrameEventGetTSStartOfExposure64(event, packet) + (caerFrameEventGetExposureLength(event) / 2));
}

static inline bool caerFrameEventIsValid(caerFrameEventConst event) {
    return (GET_NUMBITS32(event->info, VALID_MARK_SHIFT, VALID_MARK_MASK));
}

static inline void caerFrameEventValidate(caerFrameEvent event, caerFrameEventPacket packet) {
    if (!caerFrameEventIsValid(event)) {
        SET_NUMBITS32(event->info, VALID_MARK_SHIFT, VALID_MARK_MASK, 1);

        // Also increase number of events and valid events.
        // Only call this on (still) invalid events!
        caerEventPacketHeaderSetEventNumber(
            &packet->packetHeader, caerEventPacketHeaderGetEventNumber(&packet->packetHeader) + 1);
        caerEventPacketHeaderSetEventValid(
            &packet->packetHeader, caerEventPacketHeaderGetEventValid(&packet->packetHeader) + 1);
    }
    else {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event", "Called caerFrameEventValidate() on already valid event.");
    }
}

static inline void caerFrameEventInvalidate(caerFrameEvent event, caerFrameEventPacket packet) {
    if (caerFrameEventIsValid(event)) {
        CLEAR_NUMBITS32(event->info, VALID_MARK_SHIFT, VALID_MARK_MASK);

        // Also decrease number of valid events. Number of total events doesn't change.
        // Only call this on valid events!
        caerEventPacketHeaderSetEventValid(
            &packet->packetHeader, caerEventPacketHeaderGetEventValid(&packet->packetHeader) - 1);
    }
    else {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event", "Called caerFrameEventInvalidate() on already invalid event.");
    }
}

static inline size_t caerFrameEventPacketGetPixelsSize(caerFrameEventPacketConst packet) {
    // '- sizeof(uint16_t)' to compensate for pixels[1] at end of struct for C++ compatibility.
    return ((size_t) caerEventPacketHeaderGetEventSize(&packet->packetHeader)
            - (sizeof(struct caer_frame_event) - sizeof(uint16_t)));
}

static inline size_t caerFrameEventPacketGetPixelsMaxIndex(caerFrameEventPacketConst packet) {
    return (caerFrameEventPacketGetPixelsSize(packet) / sizeof(uint16_t));
}

static inline uint8_t caerFrameEventGetROIIdentifier(caerFrameEventConst event) {
    return U8T(GET_NUMBITS32(event->info, FRAME_ROI_IDENTIFIER_SHIFT, FRAME_ROI_IDENTIFIER_MASK));
}

static inline void caerFrameEventSetROIIdentifier(caerFrameEvent event, uint8_t roiIdentifier) {
    CLEAR_NUMBITS32(event->info, FRAME_ROI_IDENTIFIER_SHIFT, FRAME_ROI_IDENTIFIER_MASK);
    SET_NUMBITS32(event->info, FRAME_ROI_IDENTIFIER_SHIFT, FRAME_ROI_IDENTIFIER_MASK, roiIdentifier);
}

static inline enum caer_frame_event_color_filter caerFrameEventGetColorFilter(caerFrameEventConst event) {
    return ((enum caer_frame_event_color_filter) U8T(
        GET_NUMBITS32(event->info, FRAME_COLOR_FILTER_SHIFT, FRAME_COLOR_FILTER_MASK)));
}

static inline void caerFrameEventSetColorFilter(caerFrameEvent event, enum caer_frame_event_color_filter colorFilter) {
    CLEAR_NUMBITS32(event->info, FRAME_COLOR_FILTER_SHIFT, FRAME_COLOR_FILTER_MASK);
    SET_NUMBITS32(event->info, FRAME_COLOR_FILTER_SHIFT, FRAME_COLOR_FILTER_MASK, colorFilter);
}

static inline int32_t caerFrameEventGetLengthX(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->lengthX))));
}

static inline int32_t caerFrameEventGetLengthY(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->lengthY))));
}

static inline enum caer_frame_event_color_channels caerFrameEventGetChannelNumber(caerFrameEventConst event) {
    return ((enum caer_frame_event_color_channels) U8T(
        GET_NUMBITS32(event->info, FRAME_COLOR_CHANNELS_SHIFT, FRAME_COLOR_CHANNELS_MASK)));
}

static inline void caerFrameEventSetLengthXLengthYChannelNumber(caerFrameEvent event, int32_t lengthX, int32_t lengthY,
    enum caer_frame_event_color_channels channelNumber, caerFrameEventPacketConst packet) {
    if (lengthX <= 0 || lengthY <= 0 || channelNumber <= 0) {
        // Negative means using the 31st bit!
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventSetLengthXLengthYChannelNumber() with negative value(s)!");
        return;
    }

    // Verify lengths and color channels number don't exceed allocated space.
    size_t neededMemory = (sizeof(uint16_t) * (size_t) lengthX * (size_t) lengthY * channelNumber);

    if (neededMemory > caerFrameEventPacketGetPixelsSize(packet)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventSetLengthXLengthYChannelNumber() with "
            "values that result in requiring %zu bytes, which exceeds the "
            "maximum allocated event size of %zu bytes.",
            neededMemory, (size_t) caerEventPacketHeaderGetEventSize(&packet->packetHeader));
        return;
    }

    event->lengthX = I32T(htole32(U32T(lengthX)));
    event->lengthY = I32T(htole32(U32T(lengthY)));
    CLEAR_NUMBITS32(event->info, FRAME_COLOR_CHANNELS_SHIFT, FRAME_COLOR_CHANNELS_MASK);
    SET_NUMBITS32(event->info, FRAME_COLOR_CHANNELS_SHIFT, FRAME_COLOR_CHANNELS_MASK, channelNumber);
}

static inline size_t caerFrameEventGetPixelsMaxIndex(caerFrameEventConst event) {
    enum caer_frame_event_color_channels channels = caerFrameEventGetChannelNumber(event);
    return ((size_t) (caerFrameEventGetLengthX(event) * caerFrameEventGetLengthY(event) * I32T(channels)));
}

static inline size_t caerFrameEventGetPixelsSize(caerFrameEventConst event) {
    return (caerFrameEventGetPixelsMaxIndex(event) * sizeof(uint16_t));
}

static inline int32_t caerFrameEventGetPositionX(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->positionX))));
}

static inline void caerFrameEventSetPositionX(caerFrameEvent event, int32_t positionX) {
    event->positionX = I32T(htole32(U32T(positionX)));
}

static inline int32_t caerFrameEventGetPositionY(caerFrameEventConst event) {
    return (I32T(le32toh(U32T(event->positionY))));
}

static inline void caerFrameEventSetPositionY(caerFrameEvent event, int32_t positionY) {
    event->positionY = I32T(htole32(U32T(positionY)));
}

static inline uint16_t caerFrameEventGetPixel(caerFrameEventConst event, int32_t xAddress, int32_t yAddress) {
    // Check frame bounds first.
    if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(event)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventGetPixel() with invalid Y address of %" PRIi32 ", should be between 0 and %" PRIi32
            ".",
            yAddress, caerFrameEventGetLengthY(event) - 1);
        return (0);
    }

    int32_t xLength = caerFrameEventGetLengthX(event);

    if (xAddress < 0 || xAddress >= xLength) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventGetPixel() with invalid X address of %" PRIi32 ", should be between 0 and %" PRIi32
            ".",
            xAddress, xLength - 1);
        return (0);
    }

    // Get pixel value at specified position.
    return (le16toh(event->pixels[(yAddress * xLength) + xAddress]));
}

static inline void caerFrameEventSetPixel(
    caerFrameEvent event, int32_t xAddress, int32_t yAddress, uint16_t pixelValue) {
    // Check frame bounds first.
    if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(event)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventSetPixel() with invalid Y address of %" PRIi32 ", should be between 0 and %" PRIi32
            ".",
            yAddress, caerFrameEventGetLengthY(event) - 1);
        return;
    }

    int32_t xLength = caerFrameEventGetLengthX(event);

    if (xAddress < 0 || xAddress >= xLength) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventSetPixel() with invalid X address of %" PRIi32 ", should be between 0 and %" PRIi32
            ".",
            xAddress, xLength - 1);
        return;
    }

    // Set pixel value at specified position.
    event->pixels[(yAddress * xLength) + xAddress] = htole16(pixelValue);
}

static inline uint16_t caerFrameEventGetPixelForChannel(
    caerFrameEventConst event, int32_t xAddress, int32_t yAddress, uint8_t channel) {
    // Check frame bounds first.
    if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(event)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventGetPixelForChannel() with invalid Y address of %" PRIi32
            ", should be between 0 and %" PRIi32 ".",
            yAddress, caerFrameEventGetLengthY(event) - 1);
        return (0);
    }

    int32_t xLength = caerFrameEventGetLengthX(event);

    if (xAddress < 0 || xAddress >= xLength) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventGetPixelForChannel() with invalid X address of %" PRIi32
            ", should be between 0 and %" PRIi32 ".",
            xAddress, xLength - 1);
        return (0);
    }

    enum caer_frame_event_color_channels channelNumber = caerFrameEventGetChannelNumber(event);

    if (channel >= channelNumber) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventGetPixelForChannel() with invalid channel number of %" PRIu8
            ", should be between 0 and %" PRIu8 ".",
            channel, (uint8_t) (channelNumber - 1));
        return (0);
    }

    // Get pixel value at specified position.
    return (le16toh(event->pixels[(((yAddress * xLength) + xAddress) * U8T(channelNumber)) + channel]));
}

static inline void caerFrameEventSetPixelForChannel(
    caerFrameEvent event, int32_t xAddress, int32_t yAddress, uint8_t channel, uint16_t pixelValue) {
    // Check frame bounds first.
    if (yAddress < 0 || yAddress >= caerFrameEventGetLengthY(event)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventSetPixelForChannel() with invalid Y address of %" PRIi32
            ", should be between 0 and %" PRIi32 ".",
            yAddress, caerFrameEventGetLengthY(event) - 1);
        return;
    }

    int32_t xLength = caerFrameEventGetLengthX(event);

    if (xAddress < 0 || xAddress >= xLength) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventSetPixelForChannel() with invalid X address of %" PRIi32
            ", should be between 0 and %" PRIi32 ".",
            xAddress, xLength - 1);
        return;
    }

    enum caer_frame_event_color_channels channelNumber = caerFrameEventGetChannelNumber(event);

    if (channel >= channelNumber) {
        caerLogEHO(CAER_LOG_CRITICAL, "Frame Event",
            "Called caerFrameEventSetPixelForChannel() with invalid channel number of %" PRIu8
            ", should be between 0 and %" PRIu8 ".",
            channel, (uint8_t) (channelNumber - 1));
        return;
    }

    // Set pixel value at specified position.
    event->pixels[(((yAddress * xLength) + xAddress) * U8T(channelNumber)) + channel] = htole16(pixelValue);
}

static inline uint16_t caerFrameEventGetPixelUnsafe(caerFrameEventConst event, int32_t xAddress, int32_t yAddress) {
    // Get pixel value at specified position.
    return (le16toh(event->pixels[(yAddress * caerFrameEventGetLengthX(event)) + xAddress]));
}

static inline void caerFrameEventSetPixelUnsafe(
    caerFrameEvent event, int32_t xAddress, int32_t yAddress, uint16_t pixelValue) {
    // Set pixel value at specified position.
    event->pixels[(yAddress * caerFrameEventGetLengthX(event)) + xAddress] = htole16(pixelValue);
}

static inline uint16_t caerFrameEventGetPixelForChannelUnsafe(
    caerFrameEventConst event, int32_t xAddress, int32_t yAddress, uint8_t channel) {
    enum caer_frame_event_color_channels channelNumber = caerFrameEventGetChannelNumber(event);
    // Get pixel value at specified position.
    return (le16toh(
        event->pixels[(((yAddress * caerFrameEventGetLengthX(event)) + xAddress) * U8T(channelNumber)) + channel]));
}

static inline void caerFrameEventSetPixelForChannelUnsafe(
    caerFrameEvent event, int32_t xAddress, int32_t yAddress, uint8_t channel, uint16_t pixelValue) {
    enum caer_frame_event_color_channels channelNumber = caerFrameEventGetChannelNumber(event);
    // Set pixel value at specified position.
    event->pixels[(((yAddress * caerFrameEventGetLengthX(event)) + xAddress) * U8T(channelNumber)) + channel]
        = htole16(pixelValue);
}

static inline uint16_t *caerFrameEventGetPixelArrayUnsafe(caerFrameEvent event) {
    // Get pixels array.
    return (event->pixels);
}

static inline const uint16_t *caerFrameEventGetPixelArrayUnsafeConst(caerFrameEventConst event) {
    // Get pixels array.
    return (event->pixels);
}

#define CAER_FRAME_ITERATOR_ALL_START(FRAME_PACKET)                                                     \
    for (int32_t caerFrameIteratorCounter = 0;                                                          \
         caerFrameIteratorCounter < caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader); \
         caerFrameIteratorCounter++) {                                                                  \
        caerFrameEvent caerFrameIteratorElement = caerFrameEventPacketGetEvent(FRAME_PACKET, caerFrameIteratorCounter);

#define CAER_FRAME_CONST_ITERATOR_ALL_START(FRAME_PACKET)                                               \
    for (int32_t caerFrameIteratorCounter = 0;                                                          \
         caerFrameIteratorCounter < caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader); \
         caerFrameIteratorCounter++) {                                                                  \
        caerFrameEventConst caerFrameIteratorElement                                                    \
            = caerFrameEventPacketGetEventConst(FRAME_PACKET, caerFrameIteratorCounter);

#define CAER_FRAME_ITERATOR_ALL_END }

#define CAER_FRAME_ITERATOR_VALID_START(FRAME_PACKET)                                                   \
    for (int32_t caerFrameIteratorCounter = 0;                                                          \
         caerFrameIteratorCounter < caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader); \
         caerFrameIteratorCounter++) {                                                                  \
        caerFrameEvent caerFrameIteratorElement                                                         \
            = caerFrameEventPacketGetEvent(FRAME_PACKET, caerFrameIteratorCounter);                     \
        if (!caerFrameEventIsValid(caerFrameIteratorElement)) {                                         \
            continue;                                                                                   \
        } // Skip invalid frame events.

#define CAER_FRAME_CONST_ITERATOR_VALID_START(FRAME_PACKET)                                             \
    for (int32_t caerFrameIteratorCounter = 0;                                                          \
         caerFrameIteratorCounter < caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader); \
         caerFrameIteratorCounter++) {                                                                  \
        caerFrameEventConst caerFrameIteratorElement                                                    \
            = caerFrameEventPacketGetEventConst(FRAME_PACKET, caerFrameIteratorCounter);                \
        if (!caerFrameEventIsValid(caerFrameIteratorElement)) {                                         \
            continue;                                                                                   \
        } // Skip invalid frame events.

#define CAER_FRAME_ITERATOR_VALID_END }

#define CAER_FRAME_REVERSE_ITERATOR_ALL_START(FRAME_PACKET)                                                         \
    for (int32_t caerFrameIteratorCounter = caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader) - 1; \
         caerFrameIteratorCounter >= 0; caerFrameIteratorCounter--) {                                               \
        caerFrameEvent caerFrameIteratorElement = caerFrameEventPacketGetEvent(FRAME_PACKET, caerFrameIteratorCounter);
#define CAER_FRAME_CONST_REVERSE_ITERATOR_ALL_START(FRAME_PACKET)                                                   \
    for (int32_t caerFrameIteratorCounter = caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader) - 1; \
         caerFrameIteratorCounter >= 0; caerFrameIteratorCounter--) {                                               \
        caerFrameEventConst caerFrameIteratorElement                                                                \
            = caerFrameEventPacketGetEventConst(FRAME_PACKET, caerFrameIteratorCounter);

#define CAER_FRAME_REVERSE_ITERATOR_ALL_END }

#define CAER_FRAME_REVERSE_ITERATOR_VALID_START(FRAME_PACKET)                                                       \
    for (int32_t caerFrameIteratorCounter = caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader) - 1; \
         caerFrameIteratorCounter >= 0; caerFrameIteratorCounter--) {                                               \
        caerFrameEvent caerFrameIteratorElement                                                                     \
            = caerFrameEventPacketGetEvent(FRAME_PACKET, caerFrameIteratorCounter);                                 \
        if (!caerFrameEventIsValid(caerFrameIteratorElement)) {                                                     \
            continue;                                                                                               \
        } // Skip invalid frame events.

#define CAER_FRAME_CONST_REVERSE_ITERATOR_VALID_START(FRAME_PACKET)                                                 \
    for (int32_t caerFrameIteratorCounter = caerEventPacketHeaderGetEventNumber(&(FRAME_PACKET)->packetHeader) - 1; \
         caerFrameIteratorCounter >= 0; caerFrameIteratorCounter--) {                                               \
        caerFrameEventConst caerFrameIteratorElement                                                                \
            = caerFrameEventPacketGetEventConst(FRAME_PACKET, caerFrameIteratorCounter);                            \
        if (!caerFrameEventIsValid(caerFrameIteratorElement)) {                                                     \
            continue;                                                                                               \
        } // Skip invalid frame events.

#define CAER_FRAME_REVERSE_ITERATOR_VALID_END }

#ifdef __cplusplus
}
#endif

#endif /* LIBCAER_EVENTS_FRAME_H_ */