Program Listing for File packetContainer.h

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

#ifndef LIBCAER_EVENTS_PACKETCONTAINER_H_
#define LIBCAER_EVENTS_PACKETCONTAINER_H_

#include "common.h"

#ifdef __cplusplus
extern "C" {
#endif

PACKED_STRUCT(struct caer_event_packet_container {
    int64_t lowestEventTimestamp;
    int64_t highestEventTimestamp;
    int32_t eventsNumber;
    int32_t eventsValidNumber;
    int32_t eventPacketsNumber;
    caerEventPacketHeader eventPackets[];
});

typedef struct caer_event_packet_container *caerEventPacketContainer;
typedef const struct caer_event_packet_container *caerEventPacketContainerConst;

static inline caerEventPacketContainer caerEventPacketContainerAllocate(int32_t eventPacketsNumber) {
    if (eventPacketsNumber <= 0) {
        return (NULL);
    }

    size_t eventPacketContainerSize
        = sizeof(struct caer_event_packet_container) + ((size_t) eventPacketsNumber * sizeof(caerEventPacketHeader));

    caerEventPacketContainer packetContainer = (caerEventPacketContainer) calloc(1, eventPacketContainerSize);
    if (packetContainer == NULL) {
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Container",
            "Failed to allocate %zu bytes of memory for Event Packet Container, containing %" PRIi32
            " packets. Error: %d.",
            eventPacketContainerSize, eventPacketsNumber, errno);
        return (NULL);
    }

    // Fill in header fields. Don't care about endianness here, purely internal
    // memory construct, never meant for inter-system exchange.
    packetContainer->eventPacketsNumber    = eventPacketsNumber;
    packetContainer->lowestEventTimestamp  = -1;
    packetContainer->highestEventTimestamp = -1;

    return (packetContainer);
}

// Forward declaration for use in set operations.
static inline void caerEventPacketContainerUpdateStatistics(caerEventPacketContainer container);

static inline int32_t caerEventPacketContainerGetEventPacketsNumber(caerEventPacketContainerConst container) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (0);
    }

    return (container->eventPacketsNumber);
}

static inline void caerEventPacketContainerSetEventPacketsNumber(
    caerEventPacketContainer container, int32_t eventPacketsNumber) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return;
    }

    if (eventPacketsNumber < 0) {
        // Negative numbers (bit 31 set) are not allowed!
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Container",
            "Called caerEventPacketContainerSetEventPacketsNumber() with negative value!");
        return;
    }

    container->eventPacketsNumber = eventPacketsNumber;

    // Always update all the statics on set operation.
    caerEventPacketContainerUpdateStatistics(container);
}

static inline caerEventPacketHeader caerEventPacketContainerGetEventPacket(
    caerEventPacketContainerConst container, int32_t n) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (NULL);
    }

    // Check that we're not out of bounds.
    if (n < 0 || n >= caerEventPacketContainerGetEventPacketsNumber(container)) {
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Container",
            "Called caerEventPacketContainerGetEventPacket() with invalid event offset %" PRIi32
            ", while maximum allowed value is %" PRIi32 ". Negative values are not allowed!",
            n, caerEventPacketContainerGetEventPacketsNumber(container) - 1);
        return (NULL);
    }

    // Return a pointer to the specified event packet.
    return (container->eventPackets[n]);
}

static inline caerEventPacketHeaderConst caerEventPacketContainerGetEventPacketConst(
    caerEventPacketContainerConst container, int32_t n) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (NULL);
    }

    // Check that we're not out of bounds.
    if (n < 0 || n >= caerEventPacketContainerGetEventPacketsNumber(container)) {
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Container",
            "Called caerEventPacketContainerGetEventPacketConst() with invalid event offset %" PRIi32
            ", while maximum allowed value is %" PRIi32 ". Negative values are not allowed!",
            n, caerEventPacketContainerGetEventPacketsNumber(container) - 1);
        return (NULL);
    }

    // Return a pointer to the specified event packet.
    return (container->eventPackets[n]);
}

static inline void caerEventPacketContainerSetEventPacket(
    caerEventPacketContainer container, int32_t n, caerEventPacketHeader packetHeader) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return;
    }

    // Check that we're not out of bounds.
    if (n < 0 || n >= caerEventPacketContainerGetEventPacketsNumber(container)) {
        caerLogEHO(CAER_LOG_CRITICAL, "EventPacket Container",
            "Called caerEventPacketContainerSetEventPacket() with invalid event offset %" PRIi32
            ", while maximum allowed value is %" PRIi32 ". Negative values are not allowed!",
            n, caerEventPacketContainerGetEventPacketsNumber(container) - 1);
        return;
    }

    // Store the given event packet.
    container->eventPackets[n] = packetHeader;

    // Always update all the statics on set operation.
    caerEventPacketContainerUpdateStatistics(container);
}

static inline void caerEventPacketContainerFree(caerEventPacketContainer container) {
    if (container == NULL) {
        return;
    }

    // Free packet container and ensure all subordinate memory is also freed.
    int32_t eventPacketsNum = caerEventPacketContainerGetEventPacketsNumber(container);

    for (int32_t i = 0; i < eventPacketsNum; i++) {
        caerEventPacketHeader packetHeader = caerEventPacketContainerGetEventPacket(container, i);

        if (packetHeader != NULL) {
            free(packetHeader);
        }
    }

    free(container);
}

static inline int64_t caerEventPacketContainerGetLowestEventTimestamp(caerEventPacketContainerConst container) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (-1);
    }

    return (container->lowestEventTimestamp);
}

static inline int64_t caerEventPacketContainerGetHighestEventTimestamp(caerEventPacketContainerConst container) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (-1);
    }

    return (container->highestEventTimestamp);
}

static inline int32_t caerEventPacketContainerGetEventsNumber(caerEventPacketContainerConst container) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (0);
    }

    return (container->eventsNumber);
}

static inline int32_t caerEventPacketContainerGetEventsValidNumber(caerEventPacketContainerConst container) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (0);
    }

    return (container->eventsValidNumber);
}

#define CAER_EVENT_PACKET_CONTAINER_ITERATOR_START(PACKET_CONTAINER)                                                 \
    if ((PACKET_CONTAINER) != NULL) {                                                                                \
        for (int32_t caerEventPacketContainerIteratorCounter = 0;                                                    \
             caerEventPacketContainerIteratorCounter                                                                 \
             < caerEventPacketContainerGetEventPacketsNumber(PACKET_CONTAINER);                                      \
             caerEventPacketContainerIteratorCounter++) {                                                            \
            caerEventPacketHeader caerEventPacketContainerIteratorElement                                            \
                = caerEventPacketContainerGetEventPacket(PACKET_CONTAINER, caerEventPacketContainerIteratorCounter); \
            if (caerEventPacketContainerIteratorElement == NULL) {                                                   \
                continue;                                                                                            \
            }

#define CAER_EVENT_PACKET_CONTAINER_CONST_ITERATOR_START(PACKET_CONTAINER)      \
    if ((PACKET_CONTAINER) != NULL) {                                           \
        for (int32_t caerEventPacketContainerIteratorCounter = 0;               \
             caerEventPacketContainerIteratorCounter                            \
             < caerEventPacketContainerGetEventPacketsNumber(PACKET_CONTAINER); \
             caerEventPacketContainerIteratorCounter++) {                       \
            caerEventPacketHeaderConst caerEventPacketContainerIteratorElement  \
                = caerEventPacketContainerGetEventPacketConst(                  \
                    PACKET_CONTAINER, caerEventPacketContainerIteratorCounter); \
            if (caerEventPacketContainerIteratorElement == NULL) {              \
                continue;                                                       \
            }

#define CAER_EVENT_PACKET_CONTAINER_ITERATOR_END \
    }                                            \
    }

static inline void caerEventPacketContainerUpdateStatistics(caerEventPacketContainer container) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return;
    }

    int64_t lowestTimestamp  = -1;
    int64_t highestTimestamp = -1;
    int32_t eventsNumber     = 0;
    int32_t eventsValid      = 0;

    CAER_EVENT_PACKET_CONTAINER_CONST_ITERATOR_START(container)
    // If packet has no events, skip it, it contributes nothing to statistics.
    if (caerEventPacketHeaderGetEventNumber(caerEventPacketContainerIteratorElement) == 0) {
        continue;
    }

    // Get timestamps to update lowest/highest tracking.
    const void *firstEvent = caerGenericEventGetEvent(caerEventPacketContainerIteratorElement, 0);
    int64_t currLowestEventTimestamp
        = caerGenericEventGetTimestamp64(firstEvent, caerEventPacketContainerIteratorElement);

    const void *lastEvent = caerGenericEventGetEvent(caerEventPacketContainerIteratorElement,
        caerEventPacketHeaderGetEventNumber(caerEventPacketContainerIteratorElement) - 1);
    int64_t currHighestEventTimestamp
        = caerGenericEventGetTimestamp64(lastEvent, caerEventPacketContainerIteratorElement);

    // Update tracked timestamps (or initialize if needed).
    if ((lowestTimestamp == -1) || (lowestTimestamp > currLowestEventTimestamp)) {
        lowestTimestamp = currLowestEventTimestamp;
    }

    if ((highestTimestamp == -1) || (highestTimestamp < currHighestEventTimestamp)) {
        highestTimestamp = currHighestEventTimestamp;
    }

    eventsNumber += caerEventPacketHeaderGetEventNumber(caerEventPacketContainerIteratorElement);
    eventsValid += caerEventPacketHeaderGetEventValid(caerEventPacketContainerIteratorElement);
    CAER_EVENT_PACKET_CONTAINER_ITERATOR_END

    container->lowestEventTimestamp  = lowestTimestamp;
    container->highestEventTimestamp = highestTimestamp;
    container->eventsNumber          = eventsNumber;
    container->eventsValidNumber     = eventsValid;
}

static inline caerEventPacketHeader caerEventPacketContainerFindEventPacketByType(
    caerEventPacketContainerConst container, int16_t typeID) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (NULL);
    }

    CAER_EVENT_PACKET_CONTAINER_ITERATOR_START(container)
    if (caerEventPacketHeaderGetEventType(caerEventPacketContainerIteratorElement) == typeID) {
        // Found it, return it.
        return (caerEventPacketContainerIteratorElement);
    }
    CAER_EVENT_PACKET_CONTAINER_ITERATOR_END

    // Found nothing, return nothing.
    return (NULL);
}

static inline caerEventPacketHeaderConst caerEventPacketContainerFindEventPacketByTypeConst(
    caerEventPacketContainerConst container, int16_t typeID) {
    // Non-existing (empty) containers have no valid packets in them!
    if (container == NULL) {
        return (NULL);
    }

    CAER_EVENT_PACKET_CONTAINER_CONST_ITERATOR_START(container)
    if (caerEventPacketHeaderGetEventType(caerEventPacketContainerIteratorElement) == typeID) {
        // Found it, return it.
        return (caerEventPacketContainerIteratorElement);
    }
    CAER_EVENT_PACKET_CONTAINER_ITERATOR_END

    // Found nothing, return nothing.
    return (NULL);
}

static inline caerEventPacketContainer caerEventPacketContainerCopyAllEvents(caerEventPacketContainerConst container) {
    if (container == NULL) {
        return (NULL);
    }

    caerEventPacketContainer newContainer
        = caerEventPacketContainerAllocate(caerEventPacketContainerGetEventPacketsNumber(container));
    if (newContainer == NULL) {
        return (NULL);
    }

    CAER_EVENT_PACKET_CONTAINER_CONST_ITERATOR_START(container)
    caerEventPacketContainerSetEventPacket(newContainer, caerEventPacketContainerIteratorCounter,
        caerEventPacketCopyOnlyEvents(caerEventPacketContainerIteratorElement));
    CAER_EVENT_PACKET_CONTAINER_ITERATOR_END

    return (newContainer);
}

static inline caerEventPacketContainer caerEventPacketContainerCopyValidEvents(
    caerEventPacketContainerConst container) {
    if (container == NULL) {
        return (NULL);
    }

    caerEventPacketContainer newContainer
        = caerEventPacketContainerAllocate(caerEventPacketContainerGetEventPacketsNumber(container));
    if (newContainer == NULL) {
        return (NULL);
    }

    CAER_EVENT_PACKET_CONTAINER_CONST_ITERATOR_START(container)
    caerEventPacketContainerSetEventPacket(newContainer, caerEventPacketContainerIteratorCounter,
        caerEventPacketCopyOnlyValidEvents(caerEventPacketContainerIteratorElement));
    CAER_EVENT_PACKET_CONTAINER_ITERATOR_END

    return (newContainer);
}

#ifdef __cplusplus
}
#endif

#endif /* LIBCAER_EVENTS_PACKETCONTAINER_H_ */