Esempio n. 1
0
static void caerVisualizerEventHandlerNeuronMonitor(caerVisualizerPublicState state, const sf::Event &event) {
	// This only works with actual hardware.
	const std::string moduleLibrary = sshsNodeGetStdString(state->eventSourceConfigNode, "moduleLibrary");
	if (moduleLibrary != "caer_dynapse") {
		return;
	}

	// On release of left click.
	if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Button::Left) {
		float positionX = (float) event.mouseButton.x;
		float positionY = (float) event.mouseButton.y;

		// Adjust coordinates according to zoom factor.
		float currentZoomFactor = state->renderZoomFactor.load();
		if (currentZoomFactor > 1.0f) {
			positionX = floorf(positionX / currentZoomFactor);
			positionY = floorf(positionY / currentZoomFactor);
		}
		else if (currentZoomFactor < 1.0f) {
			positionX = floorf(positionX * currentZoomFactor);
			positionY = floorf(positionY * currentZoomFactor);
		}

		// Transform into chip ID, core ID and neuron ID.
		const struct caer_spike_event val = caerDynapseSpikeEventFromXY(U16T(positionX), U16T(positionY));

		uint8_t chipId    = caerSpikeEventGetChipID(&val);
		uint8_t coreId    = caerSpikeEventGetSourceCoreID(&val);
		uint32_t neuronId = caerSpikeEventGetNeuronID(&val);

		// Set value via SSHS.
		sshsNode neuronMonitorNode = sshsGetRelativeNode(state->eventSourceConfigNode, "NeuronMonitor/");

		char monitorKey[] = "Ux_Cy";
		monitorKey[1]     = (char) (48 + chipId);
		monitorKey[4]     = (char) (48 + coreId);

		sshsNodePutInt(neuronMonitorNode, monitorKey, I32T(neuronId));

		caerLog(CAER_LOG_NOTICE, "Visualizer", "Monitoring neuron - chip ID: %d, core ID: %d, neuron ID: %d.", chipId,
			coreId, neuronId);
	}
}
Esempio n. 2
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);
}