Beispiel #1
0
static void orderAndSendEventPackets(outputCommonState state, caerEventPacketContainer currPacketContainer) {
	// Sort container by first timestamp (required) and by type ID (convenience).
	size_t currPacketContainerSize = (size_t) caerEventPacketContainerGetEventPacketsNumber(currPacketContainer);

	qsort(currPacketContainer->eventPackets, currPacketContainerSize, sizeof(caerEventPacketHeader),
		&packetsFirstTimestampThenTypeCmp);

	// Since we just got new data, let's first check that it does conform to our expectations.
	// This means the timestamp didn't slide back! So new smallest TS is >= than last highest TS.
	// These checks are needed to avoid illegal ordering. Normal operation will never trigger
	// these, as stated in the assumptions at the start of file, but erroneous usage or mixing
	// or reordering of packet containers is possible, and has to be caught here.
	int64_t highestTimestamp = 0;

	for (size_t cpIdx = 0; cpIdx < currPacketContainerSize; cpIdx++) {
		caerEventPacketHeader cpPacket = caerEventPacketContainerGetEventPacket(currPacketContainer, (int32_t) cpIdx);

		void *cpFirstEvent = caerGenericEventGetEvent(cpPacket, 0);
		int64_t cpFirstEventTimestamp = caerGenericEventGetTimestamp64(cpFirstEvent, cpPacket);

		if (cpFirstEventTimestamp < state->lastTimestamp) {
			// Smaller TS than already sent, illegal, ignore packet.
			caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString,
				"Detected timestamp going back, expected at least %" PRIi64 " but got %" PRIi64 "."
				" Ignoring packet of type %" PRIi16 " from source %" PRIi16 ", with %" PRIi32 " events!",
				state->lastTimestamp, cpFirstEventTimestamp, caerEventPacketHeaderGetEventType(cpPacket),
				caerEventPacketHeaderGetEventSource(cpPacket), caerEventPacketHeaderGetEventNumber(cpPacket));
		}
		else {
			// Bigger or equal TS than already sent, this is good. Strict TS ordering ensures
			// that all other packets in this container are the same, so we can start sending
			// the packets from here on out to the file descriptor.
			sendEventPacket(state, cpPacket);

			// Update highest timestamp for this packet container, based upon its valid packets.
			void *cpLastEvent = caerGenericEventGetEvent(cpPacket, caerEventPacketHeaderGetEventNumber(cpPacket) - 1);
			int64_t cpLastEventTimestamp = caerGenericEventGetTimestamp64(cpLastEvent, cpPacket);

			if (cpLastEventTimestamp > highestTimestamp) {
				highestTimestamp = cpLastEventTimestamp;
			}
		}
	}

	// Remember highest timestamp for check in next iteration.
	state->lastTimestamp = highestTimestamp;
}
Beispiel #2
0
static void caerInputEDVSRun(caerModuleData moduleData, caerEventPacketContainer in, caerEventPacketContainer *out) {
	UNUSED_ARGUMENT(in);

	*out = caerDeviceDataGet(moduleData->moduleState);

	if (*out != NULL) {
		// Detect timestamp reset and call all reset functions for processors and outputs.
		caerEventPacketHeader special = caerEventPacketContainerGetEventPacket(*out, SPECIAL_EVENT);

		if ((special != NULL) && (caerEventPacketHeaderGetEventNumber(special) == 1)
			&& (caerSpecialEventPacketFindValidEventByTypeConst((caerSpecialEventPacketConst) special, TIMESTAMP_RESET)
				   != NULL)) {
			caerMainloopModuleResetOutputRevDeps(moduleData->moduleID);
		}
	}
}
Beispiel #3
0
static inline bool writeFlowEventPacketFile(flowOutputState state,
		FlowEventPacket flow) {
	caerEventPacketHeader header = (caerEventPacketHeader) flow;

	if (caerEventPacketHeaderGetEventValid(header) == 0) {
		return (false);
	}

	for (int32_t i = 0; i < caerEventPacketHeaderGetEventNumber(header); i++) {
		FlowEvent e = &(flow->events[i]);
		if (e == NULL) {
			caerLog(CAER_LOG_ERROR,SUBSYSTEM_FILE,"Event null pointer found.");
			return (false);
		}
		if (!e->hasFlow) {continue;}

		// Get event data
		uint8_t x = (uint8_t) caerPolarityEventGetX((caerPolarityEvent) e);
		uint8_t y = (uint8_t) caerPolarityEventGetY((caerPolarityEvent) e);
		int32_t t = caerPolarityEventGetTimestamp((caerPolarityEvent) e);
		bool p = caerPolarityEventGetPolarity((caerPolarityEvent) e);
		double u = e->u;
		double v = e->v;

		// Write to file
		if (state->fileLineNumber < FILE_MAX_NUMBER_OF_LINES)  {
			fprintf(state->file,"%3i,%3i,%10i,%d,%4.3f,%4.3f\n",x,y,t,p,u,v);
			state->fileLineNumber++;
		}
		else {
			// If too many lines, stop logging to prevent overrun
			if (state->fileLineNumber == FILE_MAX_NUMBER_OF_LINES) {
				caerLog(CAER_LOG_NOTICE, SUBSYSTEM_FILE,
						"File log reached limit of %d lines - "
						"no more lines will be added.", FILE_MAX_NUMBER_OF_LINES);
				state->fileLineNumber++;
			}
		}
	}
	return (true);
}
Beispiel #4
0
static inline bool sendFlowEventPacketUart(FlowEventPacket flow) {
	caerEventPacketHeader header = (caerEventPacketHeader) flow;
	uint32_t packetSize = (uint32_t) caerEventPacketHeaderGetEventNumber(header);
	if (packetSize == 0) {
		// No events to send - return
		return (false);
	}
	// Events are separated by unsigned ints of value 255. This value should
	// never occur as pixel location
	unsigned char eventSeparator = 255;

	// Iterate through packet and send events
	for (uint32_t i = 0; i < packetSize; i++) {
		FlowEvent e = &(flow->events[i]);
		if (e == NULL) {
			caerLog(CAER_LOG_ERROR,SUBSYSTEM_UART,"Event null pointer found.");
			return (false);
		}
		if (!e->hasFlow) {continue;}
		uint8_t x = (uint8_t) caerPolarityEventGetX((caerPolarityEvent) e);
		uint8_t y = (uint8_t) caerPolarityEventGetY((caerPolarityEvent) e);
		int32_t t = caerPolarityEventGetTimestamp((caerPolarityEvent) e);
		int16_t u = (int16_t) (e->u*100);
		int16_t v = (int16_t) (e->v*100);

		// Send data over UART
		if (uart_tx(sizeof(x),(unsigned char*) &x)
				|| uart_tx(sizeof(y),(unsigned char*) &y)
				|| uart_tx(sizeof(t),(unsigned char*) &t)
				|| uart_tx(sizeof(u),(unsigned char*) &u)
				|| uart_tx(sizeof(v),(unsigned char*) &v)
				|| uart_tx(sizeof(eventSeparator), &eventSeparator))  {
			caerLog(CAER_LOG_ERROR,SUBSYSTEM_UART,"Event info not fully sent.");
			return (false);
		}
	}
	return (true);
}
Beispiel #5
0
int main(int argc, char *argv[]) {
	// Install signal handler for global shutdown.
	struct sigaction shutdownAction;

	shutdownAction.sa_handler = &globalShutdownSignalHandler;
	shutdownAction.sa_flags = 0;
	sigemptyset(&shutdownAction.sa_mask);
	sigaddset(&shutdownAction.sa_mask, SIGTERM);
	sigaddset(&shutdownAction.sa_mask, SIGINT);

	if (sigaction(SIGTERM, &shutdownAction, NULL) == -1) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGTERM. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	if (sigaction(SIGINT, &shutdownAction, NULL) == -1) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGINT. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	// First of all, parse the IP:Port we need to listen on.
	// Those are for now also the only two parameters permitted.
	// If none passed, attempt to connect to default TCP IP:Port.
	const char *ipAddress = "127.0.0.1";
	uint16_t portNumber = 7777;

	if (argc != 1 && argc != 3) {
		fprintf(stderr, "Incorrect argument number. Either pass none for default IP:Port"
			"combination of 127.0.0.1:7777, or pass the IP followed by the Port.\n");
		return (EXIT_FAILURE);
	}

	// If explicitly passed, parse arguments.
	if (argc == 3) {
		ipAddress = argv[1];
		sscanf(argv[2], "%" SCNu16, &portNumber);
	}

	// Create listening socket for TCP data.
	int listenTCPSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (listenTCPSocket < 0) {
		fprintf(stderr, "Failed to create TCP socket.\n");
		return (EXIT_FAILURE);
	}

	struct sockaddr_in listenTCPAddress;
	memset(&listenTCPAddress, 0, sizeof(struct sockaddr_in));

	listenTCPAddress.sin_family = AF_INET;
	listenTCPAddress.sin_port = htons(portNumber);
	inet_aton(ipAddress, &listenTCPAddress.sin_addr); // htonl() is implicit here.

	if (connect(listenTCPSocket, (struct sockaddr *) &listenTCPAddress, sizeof(struct sockaddr_in)) < 0) {
		fprintf(stderr, "Failed to connect to remote TCP data server.\n");
		return (EXIT_FAILURE);
	}

	// 64K data buffer should be enough for the TCP event packets.
	size_t dataBufferLength = 1024 * 64;
	uint8_t *dataBuffer = malloc(dataBufferLength);

	while (!atomic_load_explicit(&globalShutdown, memory_order_relaxed)) {
		// Get packet header, to calculate packet size.
		if (!recvUntilDone(listenTCPSocket, dataBuffer, sizeof(struct caer_event_packet_header))) {
			fprintf(stderr, "Error in header recv() call: %d\n", errno);
			continue;
		}

		// Decode successfully received data.
		caerEventPacketHeader header = (caerEventPacketHeader) dataBuffer;

		int16_t eventType = caerEventPacketHeaderGetEventType(header);
		int16_t eventSource = caerEventPacketHeaderGetEventSource(header);
		int32_t eventSize = caerEventPacketHeaderGetEventSize(header);
		int32_t eventTSOffset = caerEventPacketHeaderGetEventTSOffset(header);
		int32_t eventCapacity = caerEventPacketHeaderGetEventCapacity(header);
		int32_t eventNumber = caerEventPacketHeaderGetEventNumber(header);
		int32_t eventValid = caerEventPacketHeaderGetEventValid(header);

		printf(
			"type = %" PRIi16 ", source = %" PRIi16 ", size = %" PRIi32 ", tsOffset = %" PRIi32 ", capacity = %" PRIi32 ", number = %" PRIi32 ", valid = %" PRIi32 ".\n",
			eventType, eventSource, eventSize, eventTSOffset, eventCapacity, eventNumber, eventValid);

		// Get rest of event packet, the part with the events themselves.
		if (!recvUntilDone(listenTCPSocket, dataBuffer + sizeof(struct caer_event_packet_header),
			(size_t) (eventCapacity * eventSize))) {
			fprintf(stderr, "Error in data recv() call: %d\n", errno);
			continue;
		}

		if (eventValid > 0) {
			void *firstEvent = caerGenericEventGetEvent(header, 0);
			void *lastEvent = caerGenericEventGetEvent(header, eventValid - 1);

			int32_t firstTS = caerGenericEventGetTimestamp(firstEvent, header);
			int32_t lastTS = caerGenericEventGetTimestamp(lastEvent, header);

			int32_t tsDifference = lastTS - firstTS;

			printf("Time difference in packet: %" PRIi32 " (first = %" PRIi32 ", last = %" PRIi32 ").\n", tsDifference,
				firstTS, lastTS);
		}

		printf("\n\n");
	}

	// Close connection.
	close(listenTCPSocket);

	free(dataBuffer);

	return (EXIT_SUCCESS);
}
Beispiel #6
0
static inline bool caerFrameEventPNGCompress(uint8_t **outBuffer, size_t *outSize, uint16_t *inBuffer, int32_t xSize,
	int32_t ySize, enum caer_frame_event_color_channels channels) {
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_byte **row_pointers = NULL;

	// Initialize the write struct.
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		return (false);
	}

	// Initialize the info struct.
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_write_struct(&png_ptr, NULL);
		return (false);
	}

	// Set up error handling.
	if (setjmp(png_jmpbuf(png_ptr))) {
		if (row_pointers != NULL) {
			png_free(png_ptr, row_pointers);
		}
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return (false);
	}

	// Set image attributes.
	png_set_IHDR(png_ptr, info_ptr, (png_uint_32) xSize, (png_uint_32) ySize, 16, caerFrameEventColorToLibPNG(channels),
	PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

	// Handle endianness of 16-bit depth pixels correctly.
	// PNG assumes big-endian, our Frame Event is always little-endian.
	png_set_swap(png_ptr);

	// Initialize rows of PNG.
	row_pointers = png_malloc(png_ptr, (size_t) ySize * sizeof(png_byte *));
	if (row_pointers == NULL) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		return (false);
	}

	for (size_t y = 0; y < (size_t) ySize; y++) {
		row_pointers[y] = (png_byte *) &inBuffer[y * (size_t) xSize * channels];
	}

	// Set write function to buffer one.
	struct mem_encode state = { .buffer = NULL, .size = 0 };
	png_set_write_fn(png_ptr, &state, &caerLibPNGWriteBuffer, NULL);

	// Actually write the image data.
	png_set_rows(png_ptr, info_ptr, row_pointers);
	png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

	// Free allocated memory for rows.
	png_free(png_ptr, row_pointers);

	// Destroy main structs.
	png_destroy_write_struct(&png_ptr, &info_ptr);

	// Pass out buffer with resulting PNG image.
	*outBuffer = state.buffer;
	*outSize = state.size;

	return (true);
}
#endif

static size_t compressEventPacket(outputCommonState state, caerEventPacketHeader packet, size_t packetSize) {
	// Data compression technique 1: serialize timestamps for event types that tend to repeat them a lot.
	// Currently, this means polarity events.
	if ((state->format & 0x01) && caerEventPacketHeaderGetEventType(packet) == POLARITY_EVENT) {
		// Search for runs of at least 3 events with the same timestamp, and convert them to a special
		// sequence: leave first event unchanged, but mark its timestamp as special by setting the
		// highest bit (bit 31) to one (it is forbidden for timestamps in memory to have that bit set for
		// signed-integer-only language compatibility). Then, for the second event, change its timestamp
		// to a 4-byte integer saying how many more events will follow afterwards with this same timestamp
		// (this is used for decoding), so only their data portion will be given. Then follow with those
		// event's data, back to back, with their timestamps removed.
		// So let's assume there are 6 events with TS=1234. In memory this looks like this:
		// E1(data,ts), E2(data,ts), E3(data,ts), E4(data,ts), E5(data,ts), E6(data,ts)
		// After timestamp serialization compression step:
		// E1(data,ts|0x80000000), E2(data,4), E3(data), E4(data), E5(data), E5(data)
		// This change is only in the data itself, not in the packet headers, so that we can still use the
		// eventCapacity and eventSize fields to calculate memory allocation when doing decompression.
		// As such, to correctly interpret this data, the Format flags must be correctly set. All current
		// file or network formats do specify those as mandatory in their headers, so we can rely on that.
		// Also all event types where this kind of thing makes any sense do have the timestamp as their last
		// data member in their struct, so we can use that information, stored in tsOffset header field,
		// together with eventSize, to come up with a generic implementation applicable to all other event
		// types that satisfy this condition of TS-as-last-member (so we can use that offset as event size).
		// When this is enabled, it requires full iteration thorough the whole event packet, both at
		// compression and at decompression time.
		size_t currPacketOffset = CAER_EVENT_PACKET_HEADER_SIZE; // Start here, no change to header.
		int32_t eventSize = caerEventPacketHeaderGetEventSize(packet);
		int32_t eventTSOffset = caerEventPacketHeaderGetEventTSOffset(packet);

		int32_t lastTS = -1;
		int32_t currTS = -1;
		size_t tsRun = 0;
		bool doMemMove = false; // Initially don't move memory, until we actually shrink the size.

		for (int32_t caerIteratorCounter = 0; caerIteratorCounter <= caerEventPacketHeaderGetEventNumber(packet);
			caerIteratorCounter++) {
			// Iterate until one element past the end, to flush the last run. In that particular case,
			// we don't get a new element or TS, as we'd be past the end of the array.
			if (caerIteratorCounter < caerEventPacketHeaderGetEventNumber(packet)) {
				void *caerIteratorElement = caerGenericEventGetEvent(packet, caerIteratorCounter);

				currTS = caerGenericEventGetTimestamp(caerIteratorElement, packet);
				if (currTS == lastTS) {
					// Increase size of run of same TS events currently being seen.
					tsRun++;
					continue;
				}
			}

			// TS are different, at this point look if the last run was long enough
			// and if it makes sense to compress. It does starting with 3 events.
			if (tsRun >= 3) {
				// First event to remains there, we set its TS highest bit.
				uint8_t *firstEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun--);
				caerGenericEventSetTimestamp(firstEvent, packet,
					caerGenericEventGetTimestamp(firstEvent, packet) | I32T(0x80000000));

				// Now use second event's timestamp for storing how many further events.
				uint8_t *secondEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun--);
				caerGenericEventSetTimestamp(secondEvent, packet, I32T(tsRun)); // Is at least 1.

				// Finally move modified memory where it needs to go.
				if (doMemMove) {
					memmove(((uint8_t *) packet) + currPacketOffset, firstEvent, (size_t) eventSize * 2);
				}
				else {
					doMemMove = true; // After first shrink always move memory.
				}
				currPacketOffset += (size_t) eventSize * 2;

				// Now go through remaining events and move their data close together.
				while (tsRun > 0) {
					uint8_t *thirdEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun--);
					memmove(((uint8_t *) packet) + currPacketOffset, thirdEvent, (size_t) eventTSOffset);
					currPacketOffset += (size_t) eventTSOffset;
				}
			}
			else {
				// Just copy data unchanged if no compression is possible.
				if (doMemMove) {
					uint8_t *startEvent = caerGenericEventGetEvent(packet, caerIteratorCounter - (int32_t) tsRun);
					memmove(((uint8_t *) packet) + currPacketOffset, startEvent, (size_t) eventSize * tsRun);
				}
				currPacketOffset += (size_t) eventSize * tsRun;
			}

			// Reset values for next iteration.
			lastTS = currTS;
			tsRun = 1;
		}

		return (currPacketOffset);
	}

#ifdef ENABLE_INOUT_PNG_COMPRESSION
	// Data compression technique 2: do PNG compression on frames, Grayscale and RGB(A).
	if ((state->format & 0x02) && caerEventPacketHeaderGetEventType(packet) == FRAME_EVENT) {
		size_t currPacketOffset = CAER_EVENT_PACKET_HEADER_SIZE; // Start here, no change to header.
		size_t frameHeaderSize = sizeof(struct caer_frame_event);

		CAER_FRAME_ITERATOR_ALL_START((caerFrameEventPacket) packet)
			size_t pixelSize = caerFrameEventGetPixelsSize(caerFrameIteratorElement);

			// Keep frame event header intact, compress image data, move memory close together.
			memmove(((uint8_t *) packet) + currPacketOffset, caerFrameIteratorElement, frameHeaderSize);
			currPacketOffset += frameHeaderSize;

			uint8_t *outBuffer;
			size_t outSize;
			if (!caerFrameEventPNGCompress(&outBuffer, &outSize,
				caerFrameEventGetPixelArrayUnsafe(caerFrameIteratorElement),
				caerFrameEventGetLengthX(caerFrameIteratorElement), caerFrameEventGetLengthY(caerFrameIteratorElement),
				caerFrameEventGetChannelNumber(caerFrameIteratorElement))) {
				// Failed to generate PNG.
				// Discard this frame event.
				currPacketOffset -= frameHeaderSize;
				continue;
			}

			// Check that the image didn't actually grow.
			// Add integer needed for storing PNG block length.
			if ((outSize + sizeof(int32_t)) > pixelSize) {
				caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString, "Failed to compress frame event. "
					"Image actually grew by %zu bytes to a total of %zu bytes.", (outSize - pixelSize), outSize);

				free(outBuffer);
				currPacketOffset -= frameHeaderSize;
				continue;
			}

			// Store size of PNG image block as 4 byte integer.
			int32_t outSizeInt = I32T(outSize);
			memcpy(((uint8_t *) packet) + currPacketOffset, &outSizeInt, sizeof(int32_t));
			currPacketOffset += sizeof(int32_t);

			memcpy(((uint8_t *) packet) + currPacketOffset, outBuffer, outSize);
			currPacketOffset += outSize;

			// Free allocated PNG block memory.
			free(outBuffer);
		}

		return (currPacketOffset);
	}
#endif

	return (packetSize);
}
Beispiel #7
0
/**
 * Copy event packets to the ring buffer for transfer to the output handler thread.
 *
 * @param state output module state.
 * @param packetsListSize the length of the variable-length argument list of event packets.
 * @param packetsList a variable-length argument list of event packets.
 */
static void copyPacketsToTransferRing(outputCommonState state, size_t packetsListSize, va_list packetsList) {
	caerEventPacketHeader packets[packetsListSize];
	size_t packetsSize = 0;

	// Count how many packets are really there, skipping empty event packets.
	for (size_t i = 0; i < packetsListSize; i++) {
		caerEventPacketHeader packetHeader = va_arg(packetsList, caerEventPacketHeader);

		// Found non-empty event packet.
		if (packetHeader != NULL) {
			// Get source information from the event packet.
			int16_t eventSource = caerEventPacketHeaderGetEventSource(packetHeader);

			// Check that source is unique.
			int16_t sourceID = I16T(atomic_load_explicit(&state->sourceID, memory_order_relaxed));

			if (sourceID == -1) {
				state->sourceInfoNode = caerMainloopGetSourceInfo(U16T(eventSource));
				if (state->sourceInfoNode == NULL) {
					// This should never happen, but we handle it gracefully.
					caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString,
						"Failed to get source info to setup output module.");
					return;
				}

				atomic_store(&state->sourceID, eventSource); // Remember this!
			}
			else if (sourceID != eventSource) {
				caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString,
					"An output module can only handle packets from the same source! "
						"A packet with source %" PRIi16 " was sent, but this output module expects only packets from source %" PRIi16 ".",
					eventSource, sourceID);
				continue;
			}

			// Source ID is correct, packet is not empty, we got it!
			packets[packetsSize++] = packetHeader;
		}
	}

	// There was nothing in this mainloop run!
	if (packetsSize == 0) {
		return;
	}

	// Allocate memory for event packet array structure that will get passed to output handler thread.
	caerEventPacketContainer eventPackets = caerEventPacketContainerAllocate((int32_t) packetsSize);
	if (eventPackets == NULL) {
		return;
	}

	// Handle the valid only flag here, that way we don't have to do another copy and
	// process it in the output handling thread. We get the value once here, so we do
	// the same for all packets from the same mainloop run, avoiding mid-way changes.
	bool validOnly = atomic_load_explicit(&state->validOnly, memory_order_relaxed);

	// Now copy each event packet and send the array out. Track how many packets there are.
	size_t idx = 0;

	for (size_t i = 0; i < packetsSize; i++) {
		if (validOnly) {
			caerEventPacketContainerSetEventPacket(eventPackets, (int32_t) idx,
				caerCopyEventPacketOnlyValidEvents(packets[i]));
		}
		else {
			caerEventPacketContainerSetEventPacket(eventPackets, (int32_t) idx,
				caerCopyEventPacketOnlyEvents(packets[i]));
		}

		if (caerEventPacketContainerGetEventPacket(eventPackets, (int32_t) idx) == NULL) {
			// Failed to copy packet. Signal but try to continue anyway.
			if ((validOnly && (caerEventPacketHeaderGetEventValid(packets[i]) == 0))
				|| (!validOnly && (caerEventPacketHeaderGetEventNumber(packets[i]) == 0))) {
				caerLog(CAER_LOG_NOTICE, state->parentModule->moduleSubSystemString,
					"Submitted empty event packet to output. Ignoring empty event packet.");
			}
			else {
				caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString,
					"Failed to copy event packet to output.");
			}
		}
		else {
			idx++;
		}
	}

	// We might have failed to copy all packets (unlikely).
	if (idx == 0) {
		caerEventPacketContainerFree(eventPackets);

		return;
	}

	// Reset packet container size so we only consider the packets we managed
	// to successfully copy.
	caerEventPacketContainerSetEventPacketsNumber(eventPackets, (int32_t) idx);

	retry: if (!ringBufferPut(state->transferRing, eventPackets)) {
		if (atomic_load_explicit(&state->keepPackets, memory_order_relaxed)) {
			// Retry forever if requested.
			goto retry;
		}

		caerEventPacketContainerFree(eventPackets);

		caerLog(CAER_LOG_INFO, state->parentModule->moduleSubSystemString,
			"Failed to put packet's array copy on transfer ring-buffer: full.");
		return;
	}
}
Beispiel #8
0
int main(void) {
// Install signal handler for global shutdown.
#if defined(_WIN32)
	if (signal(SIGTERM, &globalShutdownSignalHandler) == SIG_ERR) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGTERM. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	if (signal(SIGINT, &globalShutdownSignalHandler) == SIG_ERR) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGINT. Error: %d.", errno);
		return (EXIT_FAILURE);
	}
#else
	struct sigaction shutdownAction;

	shutdownAction.sa_handler = &globalShutdownSignalHandler;
	shutdownAction.sa_flags   = 0;
	sigemptyset(&shutdownAction.sa_mask);
	sigaddset(&shutdownAction.sa_mask, SIGTERM);
	sigaddset(&shutdownAction.sa_mask, SIGINT);

	if (sigaction(SIGTERM, &shutdownAction, NULL) == -1) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGTERM. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	if (sigaction(SIGINT, &shutdownAction, NULL) == -1) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGINT. Error: %d.", errno);
		return (EXIT_FAILURE);
	}
#endif

	// Open a DVS128, give it a device ID of 1, and don't care about USB bus or SN restrictions.
	caerDeviceHandle dvs128_handle = caerDeviceOpen(1, CAER_DEVICE_DVS128, 0, 0, NULL);
	if (dvs128_handle == NULL) {
		return (EXIT_FAILURE);
	}

	// Let's take a look at the information we have on the device.
	struct caer_dvs128_info dvs128_info = caerDVS128InfoGet(dvs128_handle);

	printf("%s --- ID: %d, Master: %d, DVS X: %d, DVS Y: %d, Logic: %d.\n", dvs128_info.deviceString,
		dvs128_info.deviceID, dvs128_info.deviceIsMaster, dvs128_info.dvsSizeX, dvs128_info.dvsSizeY,
		dvs128_info.logicVersion);

	// Send the default configuration before using the device.
	// No configuration is sent automatically!
	caerDeviceSendDefaultConfig(dvs128_handle);

	// Tweak some biases, to increase bandwidth in this case.
	caerDeviceConfigSet(dvs128_handle, DVS128_CONFIG_BIAS, DVS128_CONFIG_BIAS_PR, 695);
	caerDeviceConfigSet(dvs128_handle, DVS128_CONFIG_BIAS, DVS128_CONFIG_BIAS_FOLL, 867);

	// Let's verify they really changed!
	uint32_t prBias, follBias;
	caerDeviceConfigGet(dvs128_handle, DVS128_CONFIG_BIAS, DVS128_CONFIG_BIAS_PR, &prBias);
	caerDeviceConfigGet(dvs128_handle, DVS128_CONFIG_BIAS, DVS128_CONFIG_BIAS_FOLL, &follBias);

	printf("New bias values --- PR: %d, FOLL: %d.\n", prBias, follBias);

	// Now let's get start getting some data from the device. We just loop in blocking mode,
	// no notification needed regarding new events. The shutdown notification, for example if
	// the device is disconnected, should be listened to.
	caerDeviceDataStart(dvs128_handle, NULL, NULL, NULL, &usbShutdownHandler, NULL);

	// Let's turn on blocking data-get mode to avoid wasting resources.
	caerDeviceConfigSet(dvs128_handle, CAER_HOST_CONFIG_DATAEXCHANGE, CAER_HOST_CONFIG_DATAEXCHANGE_BLOCKING, true);

	while (!atomic_load_explicit(&globalShutdown, memory_order_relaxed)) {
		caerEventPacketContainer packetContainer = caerDeviceDataGet(dvs128_handle);
		if (packetContainer == NULL) {
			continue; // Skip if nothing there.
		}

		int32_t packetNum = caerEventPacketContainerGetEventPacketsNumber(packetContainer);

		printf("\nGot event container with %d packets (allocated).\n", packetNum);

		for (int32_t i = 0; i < packetNum; i++) {
			caerEventPacketHeader packetHeader = caerEventPacketContainerGetEventPacket(packetContainer, i);
			if (packetHeader == NULL) {
				printf("Packet %d is empty (not present).\n", i);
				continue; // Skip if nothing there.
			}

			printf("Packet %d of type %d -> size is %d.\n", i, caerEventPacketHeaderGetEventType(packetHeader),
				caerEventPacketHeaderGetEventNumber(packetHeader));

			// Packet 0 is always the special events packet for DVS128, while packet is the polarity events packet.
			if (i == POLARITY_EVENT) {
				caerPolarityEventPacket polarity = (caerPolarityEventPacket) packetHeader;

				// Get full timestamp and addresses of first event.
				caerPolarityEvent firstEvent = caerPolarityEventPacketGetEvent(polarity, 0);

				int32_t ts = caerPolarityEventGetTimestamp(firstEvent);
				uint16_t x = caerPolarityEventGetX(firstEvent);
				uint16_t y = caerPolarityEventGetY(firstEvent);
				bool pol   = caerPolarityEventGetPolarity(firstEvent);

				printf("First polarity event - ts: %d, x: %d, y: %d, pol: %d.\n", ts, x, y, pol);
			}
		}

		caerEventPacketContainerFree(packetContainer);
	}

	caerDeviceDataStop(dvs128_handle);

	caerDeviceClose(&dvs128_handle);

	printf("Shutdown successful.\n");

	return (EXIT_SUCCESS);
}
Beispiel #9
0
int main(void) {
// Install signal handler for global shutdown.
#if defined(_WIN32)
	if (signal(SIGTERM, &globalShutdownSignalHandler) == SIG_ERR) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGTERM. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	if (signal(SIGINT, &globalShutdownSignalHandler) == SIG_ERR) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGINT. Error: %d.", errno);
		return (EXIT_FAILURE);
	}
#else
	struct sigaction shutdownAction;

	shutdownAction.sa_handler = &globalShutdownSignalHandler;
	shutdownAction.sa_flags   = 0;
	sigemptyset(&shutdownAction.sa_mask);
	sigaddset(&shutdownAction.sa_mask, SIGTERM);
	sigaddset(&shutdownAction.sa_mask, SIGINT);

	if (sigaction(SIGTERM, &shutdownAction, NULL) == -1) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGTERM. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	if (sigaction(SIGINT, &shutdownAction, NULL) == -1) {
		caerLog(CAER_LOG_CRITICAL, "ShutdownAction", "Failed to set signal handler for SIGINT. Error: %d.", errno);
		return (EXIT_FAILURE);
	}
#endif

	// Open a DYNAPSE, give it a device ID of 1, and don't care about USB bus or SN restrictions.
	caerDeviceHandle dynapse_handle = caerDeviceOpen(1, CAER_DEVICE_DYNAPSE, 0, 0, NULL);
	if (dynapse_handle == NULL) {
		return (EXIT_FAILURE);
	}

	// Let's take a look at the information we have on the device.
	struct caer_dynapse_info dynapse_info = caerDynapseInfoGet(dynapse_handle);

	printf("%s --- ID: %d, Master: %d,  Logic: %d.\n", dynapse_info.deviceString, dynapse_info.deviceID,
		dynapse_info.deviceIsMaster, dynapse_info.logicVersion);

	// Send the default configuration before using the device.
	// No configuration is sent automatically!
	caerDeviceSendDefaultConfig(dynapse_handle);

	// Now let's get start getting some data from the device. We just loop in blocking mode,
	// no notification needed regarding new events. The shutdown notification, for example if
	// the device is disconnected, should be listened to.
	// This automatically turns on the AER and CHIP state machines.
	caerDeviceDataStart(dynapse_handle, NULL, NULL, NULL, &usbShutdownHandler, NULL);

	// Let's turn on blocking data-get mode to avoid wasting resources.
	caerDeviceConfigSet(dynapse_handle, CAER_HOST_CONFIG_DATAEXCHANGE, CAER_HOST_CONFIG_DATAEXCHANGE_BLOCKING, true);

	while (!atomic_load_explicit(&globalShutdown, memory_order_relaxed)) {
		caerEventPacketContainer packetContainer = caerDeviceDataGet(dynapse_handle);
		if (packetContainer == NULL) {
			continue; // Skip if nothing there.
		}

		int32_t packetNum = caerEventPacketContainerGetEventPacketsNumber(packetContainer);

		printf("\nGot event container with %d packets (allocated).\n", packetNum);

		for (int32_t i = 0; i < packetNum; i++) {
			caerEventPacketHeader packetHeader = caerEventPacketContainerGetEventPacket(packetContainer, i);
			if (packetHeader == NULL) {
				printf("Packet %d is empty (not present).\n", i);
				continue; // Skip if nothing there.
			}

			printf("Packet %d of type %d -> size is %d.\n", i, caerEventPacketHeaderGetEventType(packetHeader),
				caerEventPacketHeaderGetEventNumber(packetHeader));

			// Spike Events
			if (i == SPIKE_EVENT) {
				caerSpikeEventPacket spike = (caerSpikeEventPacket) packetHeader;

				// Get full timestamp and addresses of first event.
				caerSpikeEventConst firstEvent = caerSpikeEventPacketGetEventConst(spike, 0);

				int32_t ts      = caerSpikeEventGetTimestamp(firstEvent);
				uint16_t neuid  = caerSpikeEventGetNeuronID(firstEvent);
				uint16_t coreid = caerSpikeEventGetSourceCoreID(firstEvent);

				printf("First spike event - ts: %d, neu: %d, core: %d\n", ts, neuid, coreid);
			}
		}

		caerEventPacketContainerFree(packetContainer);
	}

	caerDeviceDataStop(dynapse_handle);

	caerDeviceClose(&dynapse_handle);

	printf("Shutdown successful.\n");

	return (EXIT_SUCCESS);
}
Beispiel #10
0
void DvsRosDriver::readout()
{
  caerDeviceDataStart(dvs128_handle, NULL, NULL, NULL, NULL, NULL);
  caerDeviceConfigSet(dvs128_handle, CAER_HOST_CONFIG_DATAEXCHANGE, CAER_HOST_CONFIG_DATAEXCHANGE_BLOCKING, true);

  boost::posix_time::ptime next_send_time = boost::posix_time::microsec_clock::local_time();

  dvs_msgs::EventArrayPtr event_array_msg(new dvs_msgs::EventArray());
  event_array_msg->height = dvs128_info_.dvsSizeY;
  event_array_msg->width = dvs128_info_.dvsSizeX;

  while (running_)
  {
    try
    {
      caerEventPacketContainer packetContainer = caerDeviceDataGet(dvs128_handle);
      if (packetContainer == NULL)
      {
        continue; // Skip if nothing there.
      }

      int32_t packetNum = caerEventPacketContainerGetEventPacketsNumber(packetContainer);

      for (int32_t i = 0; i < packetNum; i++)
      {
        caerEventPacketHeader packetHeader = caerEventPacketContainerGetEventPacket(packetContainer, i);
        if (packetHeader == NULL)
        {
          continue; // Skip if nothing there.
        }

        // Packet 0 is always the special events packet for DVS128, while packet is the polarity events packet.
        if (i == POLARITY_EVENT)
        {
          caerPolarityEventPacket polarity = (caerPolarityEventPacket) packetHeader;

          const int numEvents = caerEventPacketHeaderGetEventNumber(packetHeader);

          for (int j = 0; j < numEvents; j++)
          {
            // Get full timestamp and addresses of first event.
            caerPolarityEvent event = caerPolarityEventPacketGetEvent(polarity, j);

            dvs_msgs::Event e;
            e.x = caerPolarityEventGetX(event);
            e.y = caerPolarityEventGetY(event);
            e.ts = reset_time_ +
              ros::Duration().fromNSec(caerPolarityEventGetTimestamp64(event, polarity) * 1000);
            e.polarity = caerPolarityEventGetPolarity(event);

            event_array_msg->events.push_back(e);
          }

          // throttle event messages
          if (boost::posix_time::microsec_clock::local_time() > next_send_time || current_config_.streaming_rate == 0)
          {
            event_array_pub_.publish(event_array_msg);
            event_array_msg->events.clear();
            if (current_config_.streaming_rate > 0)
            {
              next_send_time += delta_;
            }
          }

          if (camera_info_manager_->isCalibrated())
          {
            sensor_msgs::CameraInfoPtr camera_info_msg(new sensor_msgs::CameraInfo(camera_info_manager_->getCameraInfo()));
            camera_info_pub_.publish(camera_info_msg);
          }
        }
      }

      caerEventPacketContainerFree(packetContainer);

      ros::spinOnce();
    }
    catch (boost::thread_interrupted&)
    {
      return;
    }
  }

  caerDeviceDataStop(dvs128_handle);
}