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); } }
/** * 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; } }
static bool caerInputEDVSInit(caerModuleData moduleData) { caerModuleLog(moduleData, CAER_LOG_DEBUG, "Initializing module ..."); // Start data acquisition, and correctly notify mainloop of new data and module of exceptional // shutdown cases (device pulled, ...). char *serialPortName = sshsNodeGetString(moduleData->moduleNode, "serialPort"); moduleData->moduleState = caerDeviceOpenSerial(U16T(moduleData->moduleID), CAER_DEVICE_EDVS, serialPortName, U32T(sshsNodeGetInt(moduleData->moduleNode, "baudRate"))); free(serialPortName); if (moduleData->moduleState == NULL) { // Failed to open device. return (false); } // Initialize per-device log-level to module log-level. caerDeviceConfigSet(moduleData->moduleState, CAER_HOST_CONFIG_LOG, CAER_HOST_CONFIG_LOG_LEVEL, atomic_load(&moduleData->moduleLogLevel)); // Put global source information into SSHS. struct caer_edvs_info devInfo = caerEDVSInfoGet(moduleData->moduleState); sshsNode sourceInfoNode = sshsGetRelativeNode(moduleData->moduleNode, "sourceInfo/"); sshsNodeCreateBool(sourceInfoNode, "deviceIsMaster", devInfo.deviceIsMaster, SSHS_FLAGS_READ_ONLY | SSHS_FLAGS_NO_EXPORT, "Timestamp synchronization support: device master status."); sshsNodeCreateInt(sourceInfoNode, "polaritySizeX", devInfo.dvsSizeX, devInfo.dvsSizeX, devInfo.dvsSizeX, SSHS_FLAGS_READ_ONLY | SSHS_FLAGS_NO_EXPORT, "Polarity events width."); sshsNodeCreateInt(sourceInfoNode, "polaritySizeY", devInfo.dvsSizeY, devInfo.dvsSizeY, devInfo.dvsSizeY, SSHS_FLAGS_READ_ONLY | SSHS_FLAGS_NO_EXPORT, "Polarity events height."); // Put source information for generic visualization, to be used to display and debug filter information. sshsNodeCreateInt(sourceInfoNode, "dataSizeX", devInfo.dvsSizeX, devInfo.dvsSizeX, devInfo.dvsSizeX, SSHS_FLAGS_READ_ONLY | SSHS_FLAGS_NO_EXPORT, "Data width."); sshsNodeCreateInt(sourceInfoNode, "dataSizeY", devInfo.dvsSizeY, devInfo.dvsSizeY, devInfo.dvsSizeY, SSHS_FLAGS_READ_ONLY | SSHS_FLAGS_NO_EXPORT, "Data height."); // Generate source string for output modules. size_t sourceStringLength = (size_t) snprintf(NULL, 0, "#Source %" PRIu16 ": eDVS4337\r\n", moduleData->moduleID); char sourceString[sourceStringLength + 1]; snprintf(sourceString, sourceStringLength + 1, "#Source %" PRIu16 ": eDVS4337\r\n", moduleData->moduleID); sourceString[sourceStringLength] = '\0'; sshsNodeCreateString(sourceInfoNode, "sourceString", sourceString, sourceStringLength, sourceStringLength, SSHS_FLAGS_READ_ONLY | SSHS_FLAGS_NO_EXPORT, "Device source information."); // Ensure good defaults for data acquisition settings. // No blocking behavior due to mainloop notification, and no auto-start of // all producers to ensure cAER settings are respected. caerDeviceConfigSet( moduleData->moduleState, CAER_HOST_CONFIG_DATAEXCHANGE, CAER_HOST_CONFIG_DATAEXCHANGE_BLOCKING, false); caerDeviceConfigSet( moduleData->moduleState, CAER_HOST_CONFIG_DATAEXCHANGE, CAER_HOST_CONFIG_DATAEXCHANGE_START_PRODUCERS, false); caerDeviceConfigSet( moduleData->moduleState, CAER_HOST_CONFIG_DATAEXCHANGE, CAER_HOST_CONFIG_DATAEXCHANGE_STOP_PRODUCERS, true); // Create default settings and send them to the device. sendDefaultConfiguration(moduleData); // Start data acquisition. bool ret = caerDeviceDataStart(moduleData->moduleState, &caerMainloopDataNotifyIncrease, &caerMainloopDataNotifyDecrease, NULL, &moduleShutdownNotify, moduleData->moduleNode); if (!ret) { // Failed to start data acquisition, close device and exit. caerDeviceClose((caerDeviceHandle *) &moduleData->moduleState); return (false); } // Add config listeners last, to avoid having them dangling if Init doesn't succeed. sshsNode biasNode = sshsGetRelativeNode(moduleData->moduleNode, "bias/"); sshsNodeAddAttributeListener(biasNode, moduleData, &biasConfigListener); sshsNode dvsNode = sshsGetRelativeNode(moduleData->moduleNode, "dvs/"); sshsNodeAddAttributeListener(dvsNode, moduleData, &dvsConfigListener); sshsNode serialNode = sshsGetRelativeNode(moduleData->moduleNode, "serial/"); sshsNodeAddAttributeListener(serialNode, moduleData, &serialConfigListener); sshsNode sysNode = sshsGetRelativeNode(moduleData->moduleNode, "system/"); sshsNodeAddAttributeListener(sysNode, moduleData, &systemConfigListener); sshsNodeAddAttributeListener(moduleData->moduleNode, moduleData, &logLevelListener); return (true); }
static bool caerInputDAVISInit(caerModuleData moduleData) { caerModuleLog(moduleData, CAER_LOG_DEBUG, "Initializing module ..."); // Start data acquisition, and correctly notify mainloop of new data and module of exceptional // shutdown cases (device pulled, ...). char *serialNumber = sshsNodeGetString(moduleData->moduleNode, "serialNumber"); moduleData->moduleState = caerDeviceOpen(U16T(moduleData->moduleID), CAER_DEVICE_DAVIS, U8T(sshsNodeGetInt(moduleData->moduleNode, "busNumber")), U8T(sshsNodeGetInt(moduleData->moduleNode, "devAddress")), serialNumber); free(serialNumber); if (moduleData->moduleState == NULL) { // Failed to open device. return (false); } struct caer_davis_info devInfo = caerDavisInfoGet(moduleData->moduleState); caerInputDAVISCommonInit(moduleData, &devInfo); // Generate sub-system string for module. char *prevAdditionStart = strchr(moduleData->moduleSubSystemString, '['); if (prevAdditionStart != NULL) { *prevAdditionStart = '\0'; } size_t subSystemStringLength = (size_t) snprintf(NULL, 0, "%s[SN %s, %" PRIu8 ":%" PRIu8 "]", moduleData->moduleSubSystemString, devInfo.deviceSerialNumber, devInfo.deviceUSBBusNumber, devInfo.deviceUSBDeviceAddress); char subSystemString[subSystemStringLength + 1]; snprintf(subSystemString, subSystemStringLength + 1, "%s[SN %s, %" PRIu8 ":%" PRIu8 "]", moduleData->moduleSubSystemString, devInfo.deviceSerialNumber, devInfo.deviceUSBBusNumber, devInfo.deviceUSBDeviceAddress); subSystemString[subSystemStringLength] = '\0'; caerModuleSetSubSystemString(moduleData, subSystemString); // Create default settings and send them to the device. createDefaultBiasConfiguration(moduleData, chipIDToName(devInfo.chipID, true), devInfo.chipID); createDefaultLogicConfiguration(moduleData, chipIDToName(devInfo.chipID, true), &devInfo); createDefaultUSBConfiguration(moduleData, chipIDToName(devInfo.chipID, true)); sendDefaultConfiguration(moduleData, &devInfo); // Start data acquisition. bool ret = caerDeviceDataStart(moduleData->moduleState, &caerMainloopDataNotifyIncrease, &caerMainloopDataNotifyDecrease, NULL, &moduleShutdownNotify, moduleData->moduleNode); if (!ret) { // Failed to start data acquisition, close device and exit. caerDeviceClose((caerDeviceHandle *) &moduleData->moduleState); return (false); } // Device related configuration has its own sub-node. sshsNode deviceConfigNode = sshsGetRelativeNode(moduleData->moduleNode, chipIDToName(devInfo.chipID, true)); // Add config listeners last, to avoid having them dangling if Init doesn't succeed. sshsNode chipNode = sshsGetRelativeNode(deviceConfigNode, "chip/"); sshsNodeAddAttributeListener(chipNode, moduleData, &chipConfigListener); sshsNode muxNode = sshsGetRelativeNode(deviceConfigNode, "multiplexer/"); sshsNodeAddAttributeListener(muxNode, moduleData, &muxConfigListener); sshsNode dvsNode = sshsGetRelativeNode(deviceConfigNode, "dvs/"); sshsNodeAddAttributeListener(dvsNode, moduleData, &dvsConfigListener); sshsNode apsNode = sshsGetRelativeNode(deviceConfigNode, "aps/"); sshsNodeAddAttributeListener(apsNode, moduleData, &apsConfigListener); sshsNode imuNode = sshsGetRelativeNode(deviceConfigNode, "imu/"); sshsNodeAddAttributeListener(imuNode, moduleData, &imuConfigListener); sshsNode extNode = sshsGetRelativeNode(deviceConfigNode, "externalInput/"); sshsNodeAddAttributeListener(extNode, moduleData, &extInputConfigListener); sshsNode usbNode = sshsGetRelativeNode(deviceConfigNode, "usb/"); sshsNodeAddAttributeListener(usbNode, moduleData, &usbConfigListener); sshsNode sysNode = sshsGetRelativeNode(moduleData->moduleNode, "system/"); sshsNodeAddAttributeListener(sysNode, moduleData, &systemConfigListener); sshsNode biasNode = sshsGetRelativeNode(deviceConfigNode, "bias/"); size_t biasNodesLength = 0; sshsNode *biasNodes = sshsNodeGetChildren(biasNode, &biasNodesLength); if (biasNodes != NULL) { for (size_t i = 0; i < biasNodesLength; i++) { // Add listener for this particular bias. sshsNodeAddAttributeListener(biasNodes[i], moduleData, &biasConfigListener); } free(biasNodes); } sshsNodeAddAttributeListener(moduleData->moduleNode, moduleData, &logLevelListener); return (true); }