Program Listing for File spike.h

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

#ifndef LIBCAER_EVENTS_SPIKE_H_
#define LIBCAER_EVENTS_SPIKE_H_

#include "common.h"

#ifdef __cplusplus
extern "C" {
#endif

#define SPIKE_SOURCE_CORE_ID_SHIFT 1
#define SPIKE_SOURCE_CORE_ID_MASK  0x0000001F
#define SPIKE_CHIP_ID_SHIFT        6
#define SPIKE_CHIP_ID_MASK         0x0000003F
#define SPIKE_NEURON_ID_SHIFT      12
#define SPIKE_NEURON_ID_MASK       0x000FFFFF

PACKED_STRUCT(struct caer_spike_event {
    uint32_t data;
    int32_t timestamp;
});

typedef struct caer_spike_event *caerSpikeEvent;
typedef const struct caer_spike_event *caerSpikeEventConst;

PACKED_STRUCT(struct caer_spike_event_packet {
    struct caer_event_packet_header packetHeader;
    struct caer_spike_event events[];
});

typedef struct caer_spike_event_packet *caerSpikeEventPacket;
typedef const struct caer_spike_event_packet *caerSpikeEventPacketConst;

static inline caerSpikeEventPacket caerSpikeEventPacketAllocate(
    int32_t eventCapacity, int16_t eventSource, int32_t tsOverflow) {
    return ((caerSpikeEventPacket) caerEventPacketAllocate(eventCapacity, eventSource, tsOverflow, SPIKE_EVENT,
        sizeof(struct caer_spike_event), offsetof(struct caer_spike_event, timestamp)));
}

static inline caerSpikeEventPacket caerSpikeEventPacketFromPacketHeader(caerEventPacketHeader header) {
    if (caerEventPacketHeaderGetEventType(header) != SPIKE_EVENT) {
        return (NULL);
    }

    return ((caerSpikeEventPacket) header);
}

static inline caerSpikeEventPacketConst caerSpikeEventPacketFromPacketHeaderConst(caerEventPacketHeaderConst header) {
    if (caerEventPacketHeaderGetEventType(header) != SPIKE_EVENT) {
        return (NULL);
    }

    return ((caerSpikeEventPacketConst) header);
}

static inline caerSpikeEvent caerSpikeEventPacketGetEvent(caerSpikeEventPacket packet, int32_t n) {
    // Check that we're not out of bounds.
    if (n < 0 || n >= caerEventPacketHeaderGetEventCapacity(&packet->packetHeader)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Spike Event",
            "Called caerSpikeEventPacketGetEvent() 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 (packet->events + n);
}

static inline caerSpikeEventConst caerSpikeEventPacketGetEventConst(caerSpikeEventPacketConst packet, int32_t n) {
    // Check that we're not out of bounds.
    if (n < 0 || n >= caerEventPacketHeaderGetEventCapacity(&packet->packetHeader)) {
        caerLogEHO(CAER_LOG_CRITICAL, "Spike Event",
            "Called caerSpikeEventPacketGetEventConst() 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 (packet->events + n);
}

static inline int32_t caerSpikeEventGetTimestamp(caerSpikeEventConst event) {
    return (I32T(le32toh(U32T(event->timestamp))));
}

static inline int64_t caerSpikeEventGetTimestamp64(caerSpikeEventConst event, caerSpikeEventPacketConst packet) {
    return (I64T((U64T(caerEventPacketHeaderGetEventTSOverflow(&packet->packetHeader)) << TS_OVERFLOW_SHIFT)
                 | U64T(caerSpikeEventGetTimestamp(event))));
}

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

    event->timestamp = I32T(htole32(U32T(timestamp)));
}

static inline bool caerSpikeEventIsValid(caerSpikeEventConst event) {
    return (GET_NUMBITS32(event->data, VALID_MARK_SHIFT, VALID_MARK_MASK));
}

static inline void caerSpikeEventValidate(caerSpikeEvent event, caerSpikeEventPacket packet) {
    if (!caerSpikeEventIsValid(event)) {
        SET_NUMBITS32(event->data, 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, "Spike Event", "Called caerSpikeEventValidate() on already valid event.");
    }
}

static inline void caerSpikeEventInvalidate(caerSpikeEvent event, caerSpikeEventPacket packet) {
    if (caerSpikeEventIsValid(event)) {
        CLEAR_NUMBITS32(event->data, 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, "Spike Event", "Called caerSpikeEventInvalidate() on already invalid event.");
    }
}

static inline uint8_t caerSpikeEventGetSourceCoreID(caerSpikeEventConst event) {
    return U8T(GET_NUMBITS32(event->data, SPIKE_SOURCE_CORE_ID_SHIFT, SPIKE_SOURCE_CORE_ID_MASK));
}

static inline void caerSpikeEventSetSourceCoreID(caerSpikeEvent event, uint8_t sourceCoreID) {
    CLEAR_NUMBITS32(event->data, SPIKE_SOURCE_CORE_ID_SHIFT, SPIKE_SOURCE_CORE_ID_MASK);
    SET_NUMBITS32(event->data, SPIKE_SOURCE_CORE_ID_SHIFT, SPIKE_SOURCE_CORE_ID_MASK, sourceCoreID);
}

static inline uint8_t caerSpikeEventGetChipID(caerSpikeEventConst event) {
    return U8T(GET_NUMBITS32(event->data, SPIKE_CHIP_ID_SHIFT, SPIKE_CHIP_ID_MASK));
}

static inline void caerSpikeEventSetChipID(caerSpikeEvent event, uint8_t chipID) {
    CLEAR_NUMBITS32(event->data, SPIKE_CHIP_ID_SHIFT, SPIKE_CHIP_ID_MASK);
    SET_NUMBITS32(event->data, SPIKE_CHIP_ID_SHIFT, SPIKE_CHIP_ID_MASK, chipID);
}

static inline uint32_t caerSpikeEventGetNeuronID(caerSpikeEventConst event) {
    return U32T(GET_NUMBITS32(event->data, SPIKE_NEURON_ID_SHIFT, SPIKE_NEURON_ID_MASK));
}

static inline void caerSpikeEventSetNeuronID(caerSpikeEvent event, uint32_t neuronID) {
    CLEAR_NUMBITS32(event->data, SPIKE_NEURON_ID_SHIFT, SPIKE_NEURON_ID_MASK);
    SET_NUMBITS32(event->data, SPIKE_NEURON_ID_SHIFT, SPIKE_NEURON_ID_MASK, neuronID);
}

#define CAER_SPIKE_ITERATOR_ALL_START(SPIKE_PACKET)                                                     \
    for (int32_t caerSpikeIteratorCounter = 0;                                                          \
         caerSpikeIteratorCounter < caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader); \
         caerSpikeIteratorCounter++) {                                                                  \
        caerSpikeEvent caerSpikeIteratorElement = caerSpikeEventPacketGetEvent(SPIKE_PACKET, caerSpikeIteratorCounter);

#define CAER_SPIKE_CONST_ITERATOR_ALL_START(SPIKE_PACKET)                                               \
    for (int32_t caerSpikeIteratorCounter = 0;                                                          \
         caerSpikeIteratorCounter < caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader); \
         caerSpikeIteratorCounter++) {                                                                  \
        caerSpikeEventConst caerSpikeIteratorElement                                                    \
            = caerSpikeEventPacketGetEventConst(SPIKE_PACKET, caerSpikeIteratorCounter);

#define CAER_SPIKE_ITERATOR_ALL_END }

#define CAER_SPIKE_ITERATOR_VALID_START(SPIKE_PACKET)                                                   \
    for (int32_t caerSpikeIteratorCounter = 0;                                                          \
         caerSpikeIteratorCounter < caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader); \
         caerSpikeIteratorCounter++) {                                                                  \
        caerSpikeEvent caerSpikeIteratorElement                                                         \
            = caerSpikeEventPacketGetEvent(SPIKE_PACKET, caerSpikeIteratorCounter);                     \
        if (!caerSpikeEventIsValid(caerSpikeIteratorElement)) {                                         \
            continue;                                                                                   \
        } // Skip invalid Spike events.

#define CAER_SPIKE_CONST_ITERATOR_VALID_START(SPIKE_PACKET)                                             \
    for (int32_t caerSpikeIteratorCounter = 0;                                                          \
         caerSpikeIteratorCounter < caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader); \
         caerSpikeIteratorCounter++) {                                                                  \
        caerSpikeEventConst caerSpikeIteratorElement                                                    \
            = caerSpikeEventPacketGetEventConst(SPIKE_PACKET, caerSpikeIteratorCounter);                \
        if (!caerSpikeEventIsValid(caerSpikeIteratorElement)) {                                         \
            continue;                                                                                   \
        } // Skip invalid Spike events.

#define CAER_SPIKE_ITERATOR_VALID_END }

#define CAER_SPIKE_REVERSE_ITERATOR_ALL_START(SPIKE_PACKET)                                                         \
    for (int32_t caerSpikeIteratorCounter = caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader) - 1; \
         caerSpikeIteratorCounter >= 0; caerSpikeIteratorCounter--) {                                               \
        caerSpikeEvent caerSpikeIteratorElement = caerSpikeEventPacketGetEvent(SPIKE_PACKET, caerSpikeIteratorCounter);
#define CAER_SPIKE_CONST_REVERSE_ITERATOR_ALL_START(SPIKE_PACKET)                                                   \
    for (int32_t caerSpikeIteratorCounter = caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader) - 1; \
         caerSpikeIteratorCounter >= 0; caerSpikeIteratorCounter--) {                                               \
        caerSpikeEventConst caerSpikeIteratorElement                                                                \
            = caerSpikeEventPacketGetEventConst(SPIKE_PACKET, caerSpikeIteratorCounter);

#define CAER_SPIKE_REVERSE_ITERATOR_ALL_END }

#define CAER_SPIKE_REVERSE_ITERATOR_VALID_START(SPIKE_PACKET)                                                       \
    for (int32_t caerSpikeIteratorCounter = caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader) - 1; \
         caerSpikeIteratorCounter >= 0; caerSpikeIteratorCounter--) {                                               \
        caerSpikeEvent caerSpikeIteratorElement                                                                     \
            = caerSpikeEventPacketGetEvent(SPIKE_PACKET, caerSpikeIteratorCounter);                                 \
        if (!caerSpikeEventIsValid(caerSpikeIteratorElement)) {                                                     \
            continue;                                                                                               \
        } // Skip invalid spike events.

#define CAER_SPIKE_CONST_REVERSE_ITERATOR_VALID_START(SPIKE_PACKET)                                                 \
    for (int32_t caerSpikeIteratorCounter = caerEventPacketHeaderGetEventNumber(&(SPIKE_PACKET)->packetHeader) - 1; \
         caerSpikeIteratorCounter >= 0; caerSpikeIteratorCounter--) {                                               \
        caerSpikeEventConst caerSpikeIteratorElement                                                                \
            = caerSpikeEventPacketGetEventConst(SPIKE_PACKET, caerSpikeIteratorCounter);                            \
        if (!caerSpikeEventIsValid(caerSpikeIteratorElement)) {                                                     \
            continue;                                                                                               \
        } // Skip invalid spike events.

#define CAER_SPIKE_REVERSE_ITERATOR_VALID_END }

#ifdef __cplusplus
}
#endif

#endif /* LIBCAER_EVENTS_SPIKE_H_ */