Program Listing for File common.h

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

#ifndef LIBCAER_EVENTS_COMMON_H_
#define LIBCAER_EVENTS_COMMON_H_

#include "../libcaer.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifndef CAER_EVENTS_HEADER_ONLY
#   define caerLogEHO caerLog
#else
static inline void caerLogEHO(enum caer_log_level logLevel, const char *subSystem, const char *format, ...) {
    // Ignore logLevel, all event packet messages are critical.
    (void) (logLevel);

    printf("%s: ", subSystem);

    va_list argumentList;
    va_start(argumentList, format);
    vprintf(format, argumentList);
    va_end(argumentList);

    printf("\n");
}
#endif

#define VALID_MARK_SHIFT 0
#define VALID_MARK_MASK  0x00000001

#define TS_OVERFLOW_SHIFT 31

enum caer_default_event_types {
    SPECIAL_EVENT   = 0,
    POLARITY_EVENT  = 1,
    FRAME_EVENT     = 2,
    IMU6_EVENT      = 3,
    IMU9_EVENT      = 4,
    SAMPLE_EVENT    = 5,
    EAR_EVENT       = 6,
    CONFIG_EVENT    = 7,
    POINT1D_EVENT   = 8,
    POINT2D_EVENT   = 9,
    POINT3D_EVENT   = 10,
    POINT4D_EVENT   = 11,
    SPIKE_EVENT     = 12,
    MATRIX4x4_EVENT = 13,
};

#define CAER_DEFAULT_EVENT_TYPES_COUNT 14

#define CAER_EVENT_PACKET_HEADER_SIZE 28

PACKED_STRUCT(struct caer_event_packet_header {
    int16_t eventType;
    int16_t eventSource;
    int32_t eventSize;
    int32_t eventTSOffset;
    int32_t eventTSOverflow;
    int32_t eventCapacity;
    int32_t eventNumber;
    int32_t eventValid;
});

typedef struct caer_event_packet_header *caerEventPacketHeader;
typedef const struct caer_event_packet_header *caerEventPacketHeaderConst;

static inline int16_t caerEventPacketHeaderGetEventType(caerEventPacketHeaderConst header) {
    return (I16T(le16toh(U16T(header->eventType))));
}

static inline void caerEventPacketHeaderSetEventType(caerEventPacketHeader header, int16_t eventType) {
    if (eventType < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(
            CAER_LOG_CRITICAL, "EventPacket Header", "Called caerEventPacketHeaderSetEventType() with negative value!");
        return;
    }

    header->eventType = I16T(htole16(U16T(eventType)));
}

static inline int16_t caerEventPacketHeaderGetEventSource(caerEventPacketHeaderConst header) {
    return (I16T(le16toh(U16T(header->eventSource))));
}

static inline void caerEventPacketHeaderSetEventSource(caerEventPacketHeader header, int16_t eventSource) {
    if (eventSource < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Header",
            "Called caerEventPacketHeaderSetEventSource() with negative value!");
        return;
    }

    header->eventSource = I16T(htole16(U16T(eventSource)));
}

static inline int32_t caerEventPacketHeaderGetEventSize(caerEventPacketHeaderConst header) {
    return (I32T(le32toh(U32T(header->eventSize))));
}

static inline void caerEventPacketHeaderSetEventSize(caerEventPacketHeader header, int32_t eventSize) {
    if (eventSize < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(
            CAER_LOG_CRITICAL, "EventPacket Header", "Called caerEventPacketHeaderSetEventSize() with negative value!");
        return;
    }

    header->eventSize = I32T(htole32(U32T(eventSize)));
}

static inline int32_t caerEventPacketHeaderGetEventTSOffset(caerEventPacketHeaderConst header) {
    return (I32T(le32toh(U32T(header->eventTSOffset))));
}

static inline void caerEventPacketHeaderSetEventTSOffset(caerEventPacketHeader header, int32_t eventTSOffset) {
    if (eventTSOffset < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Header",
            "Called caerEventPacketHeaderSetEventTSOffset() with negative value!");
        return;
    }

    header->eventTSOffset = I32T(htole32(U32T(eventTSOffset)));
}

static inline int32_t caerEventPacketHeaderGetEventTSOverflow(caerEventPacketHeaderConst header) {
    return (I32T(le32toh(U32T(header->eventTSOverflow))));
}

static inline void caerEventPacketHeaderSetEventTSOverflow(caerEventPacketHeader header, int32_t eventTSOverflow) {
    if (eventTSOverflow < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Header",
            "Called caerEventPacketHeaderSetEventTSOverflow() with negative value!");
        return;
    }

    header->eventTSOverflow = I32T(htole32(U32T(eventTSOverflow)));
}

static inline int32_t caerEventPacketHeaderGetEventCapacity(caerEventPacketHeaderConst header) {
    return (I32T(le32toh(U32T(header->eventCapacity))));
}

static inline void caerEventPacketHeaderSetEventCapacity(caerEventPacketHeader header, int32_t eventsCapacity) {
    if (eventsCapacity < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Header",
            "Called caerEventPacketHeaderSetEventCapacity() with negative value!");
        return;
    }

    header->eventCapacity = I32T(htole32(U32T(eventsCapacity)));
}

static inline int32_t caerEventPacketHeaderGetEventNumber(caerEventPacketHeaderConst header) {
    return (I32T(le32toh(U32T(header->eventNumber))));
}

static inline void caerEventPacketHeaderSetEventNumber(caerEventPacketHeader header, int32_t eventsNumber) {
    if (eventsNumber < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Header",
            "Called caerEventPacketHeaderSetEventNumber() with negative value!");
        return;
    }

    header->eventNumber = I32T(htole32(U32T(eventsNumber)));
}

static inline int32_t caerEventPacketHeaderGetEventValid(caerEventPacketHeaderConst header) {
    return (I32T(le32toh(U32T(header->eventValid))));
}

static inline void caerEventPacketHeaderSetEventValid(caerEventPacketHeader header, int32_t eventsValid) {
    if (eventsValid < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Header",
            "Called caerEventPacketHeaderSetEventValid() with negative value!");
        return;
    }

    header->eventValid = I32T(htole32(U32T(eventsValid)));
}

static inline const void *caerGenericEventGetEvent(caerEventPacketHeaderConst headerPtr, int32_t n) {
    // Check that we're not out of bounds.
    // Accessing elements after EventNumber() but before EventCapacity() doesn't
    // make any sense here for the Generic Event getter, as we only support
    // reading/querying data from those events, and that would always fail for
    // those empty events, as they are all zeroed out.
    if (n < 0 || n >= caerEventPacketHeaderGetEventNumber(headerPtr)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Generic Event",
            "Called caerGenericEventGetEvent() with invalid event offset %" PRIi32
            ", while maximum allowed value is %" PRIi32 ". Negative values are not allowed!",
            n, caerEventPacketHeaderGetEventNumber(headerPtr) - 1);
        return (NULL);
    }

    // Return a pointer to the specified event.
    return (((const uint8_t *) headerPtr)
            + (CAER_EVENT_PACKET_HEADER_SIZE + U64T(n * caerEventPacketHeaderGetEventSize(headerPtr))));
}

static inline int32_t caerGenericEventGetTimestamp(const void *eventPtr, caerEventPacketHeaderConst headerPtr) {
    return (I32T(le32toh(U32T(*(
        (const int32_t *) (((const uint8_t *) eventPtr) + U64T(caerEventPacketHeaderGetEventTSOffset(headerPtr))))))));
}

static inline int64_t caerGenericEventGetTimestamp64(const void *eventPtr, caerEventPacketHeaderConst headerPtr) {
    return (I64T((U64T(caerEventPacketHeaderGetEventTSOverflow(headerPtr)) << TS_OVERFLOW_SHIFT)
                 | U64T(caerGenericEventGetTimestamp(eventPtr, headerPtr))));
}

static inline bool caerGenericEventIsValid(const void *eventPtr) {
    // Look at first byte of event memory's lowest bit.
    // This should always work since first event member must contain the valid mark
    // and memory is little-endian, so lowest bit must be in first byte of memory.
    return (*((const uint8_t *) eventPtr) & VALID_MARK_MASK);
}

static inline bool caerGenericEventCopy(void *eventPtrDestination, const void *eventPtrSource,
    caerEventPacketHeaderConst headerPtrDestination, caerEventPacketHeaderConst headerPtrSource) {
    if ((caerEventPacketHeaderGetEventType(headerPtrDestination) != caerEventPacketHeaderGetEventType(headerPtrSource))
        || (caerEventPacketHeaderGetEventSize(headerPtrDestination)
            != caerEventPacketHeaderGetEventSize(headerPtrSource))
        || (caerEventPacketHeaderGetEventTSOverflow(headerPtrDestination)
            != caerEventPacketHeaderGetEventTSOverflow(headerPtrSource))) {
        return (false);
    }

    memcpy(eventPtrDestination, eventPtrSource, (size_t) caerEventPacketHeaderGetEventSize(headerPtrDestination));
    return (true);
}

#define CAER_ITERATOR_ALL_START(PACKET_HEADER, EVENT_TYPE)                                                          \
    for (int32_t caerIteratorCounter = 0; caerIteratorCounter < caerEventPacketHeaderGetEventNumber(PACKET_HEADER); \
         caerIteratorCounter++) {                                                                                   \
        EVENT_TYPE caerIteratorElement = (EVENT_TYPE) caerGenericEventGetEvent(PACKET_HEADER, caerIteratorCounter);

#define CAER_ITERATOR_ALL_END }

#define CAER_ITERATOR_VALID_START(PACKET_HEADER, EVENT_TYPE)                                                        \
    for (int32_t caerIteratorCounter = 0; caerIteratorCounter < caerEventPacketHeaderGetEventNumber(PACKET_HEADER); \
         caerIteratorCounter++) {                                                                                   \
        EVENT_TYPE caerIteratorElement = (EVENT_TYPE) caerGenericEventGetEvent(PACKET_HEADER, caerIteratorCounter); \
        if (!caerGenericEventIsValid(caerIteratorElement)) {                                                        \
            continue;                                                                                               \
        } // Skip invalid events.

#define CAER_ITERATOR_VALID_END }

static inline int64_t caerEventPacketGetDataSize(caerEventPacketHeaderConst header) {
    return (I64T(caerEventPacketHeaderGetEventSize(header)) * I64T(caerEventPacketHeaderGetEventCapacity(header)));
}

static inline int64_t caerEventPacketGetSize(caerEventPacketHeaderConst header) {
    return (CAER_EVENT_PACKET_HEADER_SIZE + caerEventPacketGetDataSize(header));
}

static inline int64_t caerEventPacketGetDataSizeEvents(caerEventPacketHeaderConst header) {
    return (I64T(caerEventPacketHeaderGetEventSize(header)) * I64T(caerEventPacketHeaderGetEventNumber(header)));
}

static inline int64_t caerEventPacketGetSizeEvents(caerEventPacketHeaderConst header) {
    return (CAER_EVENT_PACKET_HEADER_SIZE + caerEventPacketGetDataSizeEvents(header));
}

static inline bool caerEventPacketEquals(
    caerEventPacketHeaderConst firstPacket, caerEventPacketHeaderConst secondPacket) {
    // If any of the packets is NULL, they can't be equal.
    if (firstPacket == NULL || secondPacket == NULL) {
        return (false);
    }

    // If both packets are the same packet (pointer equal),
    // they are of course indeed equal packets.
    if (firstPacket == secondPacket) {
        return (true);
    }

    // Actually compare memory now. We compare header equality, and
    // all events up to eventNumber. The remaining events up to
    // eventCapacity are by definition all zeroed out, so must be
    // equal, if the capacity is the same, which it is, as we check
    // for that when ensuring header equality.
    if (memcmp(firstPacket, secondPacket, CAER_EVENT_PACKET_HEADER_SIZE) != 0) {
        return (false);
    }

    size_t memCmpSize
        = (size_t) (caerEventPacketHeaderGetEventNumber(firstPacket) * caerEventPacketHeaderGetEventSize(firstPacket));
    if (memcmp(((const uint8_t *) firstPacket) + CAER_EVENT_PACKET_HEADER_SIZE,
            ((const uint8_t *) secondPacket) + CAER_EVENT_PACKET_HEADER_SIZE, memCmpSize)
        != 0) {
        return (false);
    }

    return (true);
}

static inline void caerEventPacketClear(caerEventPacketHeader packet) {
    // Handle empty event packets.
    if (packet == NULL) {
        return;
    }

    // Set events up to eventNumber to zero. The remaining events up to
    // eventCapacity are by definition all zeroed out, so nothing to do
    // there. Also reset the eventValid and eventNumber header fields.
    size_t memZeroSize
        = (size_t) (caerEventPacketHeaderGetEventNumber(packet) * caerEventPacketHeaderGetEventSize(packet));
    memset(((uint8_t *) packet) + CAER_EVENT_PACKET_HEADER_SIZE, 0, memZeroSize);

    caerEventPacketHeaderSetEventValid(packet, 0);
    caerEventPacketHeaderSetEventNumber(packet, 0);
}

static inline void caerEventPacketClean(caerEventPacketHeader packet) {
    // Handle empty event packets.
    if (packet == NULL) {
        return;
    }

    // Calculate needed memory for new event packet.
    int32_t eventValid  = caerEventPacketHeaderGetEventValid(packet);
    int32_t eventNumber = caerEventPacketHeaderGetEventNumber(packet);

    // If we have no invalid events, we're already done.
    if (eventValid == eventNumber) {
        return;
    }

    int32_t eventSize     = caerEventPacketHeaderGetEventSize(packet);
    int32_t eventCapacity = caerEventPacketHeaderGetEventCapacity(packet);

    // Move all valid events close together. Must check every event for validity!
    size_t offset = CAER_EVENT_PACKET_HEADER_SIZE;

    CAER_ITERATOR_VALID_START(packet, const void *)
    void *dest = ((uint8_t *) packet) + offset;

    if (dest != caerIteratorElement) {
        memcpy(dest, caerIteratorElement, (size_t) eventSize);
        offset += (size_t) eventSize;
    }
}

// Reset remaining memory, up to capacity, to zero (all events invalid).
memset(((uint8_t *) packet) + offset, 0, (size_t) ((eventCapacity - eventValid) * eventSize));

// Event capacity remains unchanged, event number shrunk to event valid number.
caerEventPacketHeaderSetEventNumber(packet, eventValid);
}

static inline caerEventPacketHeader caerEventPacketResize(caerEventPacketHeader packet, int32_t newEventCapacity) {
    if (packet == NULL || newEventCapacity <= 0) {
        return (NULL);
    }

    // Always clean for consistency with shrink case (side-effects guarantee).
    caerEventPacketClean(packet);

    int32_t oldEventCapacity = caerEventPacketHeaderGetEventCapacity(packet);

    if (oldEventCapacity == newEventCapacity) {
        // Nothing to do in this case.
        return (packet);
    }

    int32_t eventSize         = caerEventPacketHeaderGetEventSize(packet);
    size_t newEventPacketSize = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (newEventCapacity * eventSize);

    // Reallocate memory used to hold events.
    packet = (caerEventPacketHeader) realloc(packet, newEventPacketSize);
    if (packet == NULL) {
        caerLogEHO(CAER_LOG_CRITICAL, "Event Packet",
            "Failed to reallocate %zu bytes of memory for resizing Event Packet of capacity %" PRIi32
            " to new capacity of %" PRIi32 ". Error: %d.",
            newEventPacketSize, oldEventCapacity, newEventCapacity, errno);
        return (NULL);
    }

    if (newEventCapacity > oldEventCapacity) {
        // Capacity increased: we simply zero out the newly added events.
        size_t oldEventPacketSize = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (oldEventCapacity * eventSize);

        memset(
            ((uint8_t *) packet) + oldEventPacketSize, 0, (size_t) ((newEventCapacity - oldEventCapacity) * eventSize));
    }
    else {
        // Capacity decreased: the events were cleaned, so eventValid == eventNumber.
        // They also are all together in memory. Thus we can simply keep the current
        // eventValid/eventNumber counts if the capacity is still bigger or equal to
        // them, or, if new capacity is smaller, we reset them to that value.
        int32_t oldEventNumber = caerEventPacketHeaderGetEventNumber(packet);

        if (newEventCapacity < oldEventNumber) {
            caerEventPacketHeaderSetEventValid(packet, newEventCapacity);
            caerEventPacketHeaderSetEventNumber(packet, newEventCapacity);
        }
    }

    // Update capacity header field.
    caerEventPacketHeaderSetEventCapacity(packet, newEventCapacity);

    return (packet);
}

static inline caerEventPacketHeader caerEventPacketGrow(caerEventPacketHeader packet, int32_t newEventCapacity) {
    if (packet == NULL || newEventCapacity <= 0) {
        return (NULL);
    }

    int32_t oldEventCapacity = caerEventPacketHeaderGetEventCapacity(packet);

    if (newEventCapacity <= oldEventCapacity) {
        caerLogEHO(CAER_LOG_CRITICAL, "Event Packet",
            "Called caerEventPacketGrow() with a new capacity value (%" PRIi32
            ") that is equal or smaller than the old one (%" PRIi32 "). "
            "Only strictly growing an event packet is supported!",
            newEventCapacity, oldEventCapacity);
        return (NULL);
    }

    int32_t eventSize         = caerEventPacketHeaderGetEventSize(packet);
    size_t newEventPacketSize = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (newEventCapacity * eventSize);

    // Grow memory used to hold events.
    packet = (caerEventPacketHeader) realloc(packet, newEventPacketSize);
    if (packet == NULL) {
        caerLogEHO(CAER_LOG_CRITICAL, "Event Packet",
            "Failed to reallocate %zu bytes of memory for growing Event Packet of capacity %" PRIi32
            " to new capacity of %" PRIi32 ". Error: %d.",
            newEventPacketSize, oldEventCapacity, newEventCapacity, errno);
        return (NULL);
    }

    // Zero out new event memory (all events invalid).
    size_t oldEventPacketSize = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (oldEventCapacity * eventSize);

    memset(((uint8_t *) packet) + oldEventPacketSize, 0, (size_t) ((newEventCapacity - oldEventCapacity) * eventSize));

    // Update capacity header field.
    caerEventPacketHeaderSetEventCapacity(packet, newEventCapacity);

    return (packet);
}

static inline caerEventPacketHeader caerEventPacketAppend(
    caerEventPacketHeader packet, caerEventPacketHeader appendPacket) {
    if (packet == NULL) {
        return (NULL);
    }

    // Support appending nothing, the result is the unmodified input.
    if (appendPacket == NULL) {
        return (packet);
    }

    // Check that the two packets are of the same type and size, and have the same TSOverflow epoch.
    if ((caerEventPacketHeaderGetEventType(packet) != caerEventPacketHeaderGetEventType(appendPacket))
        || (caerEventPacketHeaderGetEventSize(packet) != caerEventPacketHeaderGetEventSize(appendPacket))
        || (caerEventPacketHeaderGetEventTSOverflow(packet) != caerEventPacketHeaderGetEventTSOverflow(appendPacket))) {
        return (NULL);
    }

    int32_t packetEventValid    = caerEventPacketHeaderGetEventValid(packet);
    int32_t packetEventNumber   = caerEventPacketHeaderGetEventNumber(packet);
    int32_t packetEventCapacity = caerEventPacketHeaderGetEventCapacity(packet);

    int32_t appendPacketEventValid    = caerEventPacketHeaderGetEventValid(appendPacket);
    int32_t appendPacketEventNumber   = caerEventPacketHeaderGetEventNumber(appendPacket);
    int32_t appendPacketEventCapacity = caerEventPacketHeaderGetEventCapacity(appendPacket);

    int32_t eventSize = caerEventPacketHeaderGetEventSize(packet); // Is the same! Checked above.
    size_t newEventPacketSize
        = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) ((packetEventCapacity + appendPacketEventCapacity) * eventSize);

    // Grow memory used to hold events.
    packet = (caerEventPacketHeader) realloc(packet, newEventPacketSize);
    if (packet == NULL) {
        caerLogEHO(CAER_LOG_CRITICAL, "Event Packet",
            "Failed to reallocate %zu bytes of memory for appending Event Packet of capacity %" PRIi32
            " to Event Packet of capacity %" PRIi32 ". Error: %d.",
            newEventPacketSize, appendPacketEventCapacity, packetEventCapacity, errno);
        return (NULL);
    }

    // Copy appendPacket event memory at start of free space in packet.
    memcpy(((uint8_t *) packet) + CAER_EVENT_PACKET_HEADER_SIZE + (packetEventNumber * eventSize),
        ((uint8_t *) appendPacket) + CAER_EVENT_PACKET_HEADER_SIZE, (size_t) (appendPacketEventNumber * eventSize));

    // Zero out remaining event memory (all events invalid).
    memset(((uint8_t *) packet) + CAER_EVENT_PACKET_HEADER_SIZE
               + ((packetEventNumber + appendPacketEventNumber) * eventSize),
        0,
        (size_t) (((packetEventCapacity + appendPacketEventCapacity) - (packetEventNumber + appendPacketEventNumber))
                  * eventSize));

    // Update header fields.
    caerEventPacketHeaderSetEventValid(packet, (packetEventValid + appendPacketEventValid));
    caerEventPacketHeaderSetEventNumber(packet, (packetEventNumber + appendPacketEventNumber));
    caerEventPacketHeaderSetEventCapacity(packet, (packetEventCapacity + appendPacketEventCapacity));

    return (packet);
}

static inline caerEventPacketHeader caerEventPacketCopy(caerEventPacketHeaderConst packet) {
    // Handle empty event packets.
    if (packet == NULL) {
        return (NULL);
    }

    // Calculate needed memory for new event packet.
    int32_t eventSize     = caerEventPacketHeaderGetEventSize(packet);
    int32_t eventNumber   = caerEventPacketHeaderGetEventNumber(packet);
    int32_t eventCapacity = caerEventPacketHeaderGetEventCapacity(packet);
    size_t packetMem      = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (eventSize * eventCapacity);
    size_t dataMem        = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (eventSize * eventNumber);

    // Allocate memory for new event packet.
    caerEventPacketHeader packetCopy = (caerEventPacketHeader) malloc(packetMem);
    if (packetCopy == NULL) {
        // Failed to allocate memory.
        return (NULL);
    }

    // Copy the data over.
    memcpy(packetCopy, packet, dataMem);

    // Zero out the rest of the packet.
    memset(((uint8_t *) packetCopy) + dataMem, 0, packetMem - dataMem);

    return (packetCopy);
}

static inline caerEventPacketHeader caerEventPacketCopyOnlyEvents(caerEventPacketHeaderConst packet) {
    // Handle empty event packets.
    if (packet == NULL) {
        return (NULL);
    }

    // Calculate needed memory for new event packet.
    int32_t eventSize   = caerEventPacketHeaderGetEventSize(packet);
    int32_t eventNumber = caerEventPacketHeaderGetEventNumber(packet);

    if (eventNumber == 0) {
        // No copy possible if result is empty (capacity=0).
        return (NULL);
    }

    size_t packetMem = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (eventSize * eventNumber);

    // Allocate memory for new event packet.
    caerEventPacketHeader packetCopy = (caerEventPacketHeader) malloc(packetMem);
    if (packetCopy == NULL) {
        // Failed to allocate memory.
        return (NULL);
    }

    // Copy the data over.
    memcpy(packetCopy, packet, packetMem);

    // Set the event capacity to the event number, since we only allocated
    // memory for that many events.
    caerEventPacketHeaderSetEventCapacity(packetCopy, eventNumber);

    return (packetCopy);
}

static inline caerEventPacketHeader caerEventPacketCopyOnlyValidEvents(caerEventPacketHeaderConst packet) {
    // Handle empty event packets.
    if (packet == NULL) {
        return (NULL);
    }

    // Calculate needed memory for new event packet.
    int32_t eventSize  = caerEventPacketHeaderGetEventSize(packet);
    int32_t eventValid = caerEventPacketHeaderGetEventValid(packet);

    if (eventValid == 0) {
        // No copy possible if result is empty (capacity=0).
        return (NULL);
    }

    size_t packetMem = CAER_EVENT_PACKET_HEADER_SIZE + (size_t) (eventSize * eventValid);

    // Allocate memory for new event packet.
    caerEventPacketHeader packetCopy = (caerEventPacketHeader) malloc(packetMem);
    if (packetCopy == NULL) {
        // Failed to allocate memory.
        return (NULL);
    }

    // First copy over the header.
    memcpy(packetCopy, packet, CAER_EVENT_PACKET_HEADER_SIZE);

    // Copy the data over. Must check every event for validity!
    size_t offset = CAER_EVENT_PACKET_HEADER_SIZE;

    CAER_ITERATOR_VALID_START(packet, const void *)
    memcpy(((uint8_t *) packetCopy) + offset, caerIteratorElement, (size_t) eventSize);
    offset += (size_t) eventSize;
}

// Set the event capacity and the event number to the number of
// valid events, since we only copied those.
caerEventPacketHeaderSetEventCapacity(packetCopy, eventValid);
caerEventPacketHeaderSetEventNumber(packetCopy, eventValid);

return (packetCopy);
}

static inline caerEventPacketHeader caerEventPacketAllocate(int32_t eventCapacity, int16_t eventSource,
    int32_t tsOverflow, int16_t eventType, int32_t eventSize, int32_t eventTSOffset) {
    if ((eventCapacity <= 0) || (eventSource < 0) || (tsOverflow < 0) || (eventType < 0) || (eventSize <= 0)
        || (eventTSOffset < 0)) {
        return (NULL);
    }

    size_t eventPacketSize = CAER_EVENT_PACKET_HEADER_SIZE + ((size_t) eventCapacity * (size_t) eventSize);

    // Zero out event memory (all events invalid).
    caerEventPacketHeader packet = (caerEventPacketHeader) calloc(1, eventPacketSize);
    if (packet == NULL) {
        caerLogEHO(CAER_LOG_CRITICAL, "Event Packet",
            "Failed to allocate %zu bytes of memory for Event Packet of type %" PRIi16 ", capacity %" PRIi32
            " from source %" PRIi16 ". Error: %d.",
            eventPacketSize, eventType, eventCapacity, eventSource, errno);
        return (NULL);
    }

    // Fill in header fields.
    caerEventPacketHeaderSetEventType(packet, eventType);
    caerEventPacketHeaderSetEventSource(packet, eventSource);
    caerEventPacketHeaderSetEventSize(packet, eventSize);
    caerEventPacketHeaderSetEventTSOffset(packet, eventTSOffset);
    caerEventPacketHeaderSetEventTSOverflow(packet, tsOverflow);
    caerEventPacketHeaderSetEventCapacity(packet, eventCapacity);

    return (packet);
}

#ifdef __cplusplus
}
#endif

#endif /* LIBCAER_EVENTS_COMMON_H_ */