Пример #1
0
static bool caerOutputFileInit(caerModuleData moduleData) {
	// First, always create all needed setting nodes, set their default values
	// and add their listeners.
	char *userHomeDir = getUserHomeDirectory(moduleData);
	if (userHomeDir == NULL) {
		// caerModuleLog() called inside getUserHomeDirectory().
		return (false);
	}

	sshsNodeCreateString(moduleData->moduleNode, "directory", userHomeDir, 1, (PATH_MAX - MAX_PREFIX_LENGTH),
		SSHS_FLAGS_NORMAL, "Directory to write output data files in.");
	free(userHomeDir);

	// Support file-chooser in GUI, select any directory.
	sshsNodeCreateAttributeFileChooser(moduleData->moduleNode, "directory", "DIRECTORY");

	sshsNodeCreateString(moduleData->moduleNode, "prefix", DEFAULT_PREFIX, 1, MAX_PREFIX_LENGTH, SSHS_FLAGS_NORMAL,
		"Output data files name prefix.");

	// Generate current file name and open it.
	char *directory = sshsNodeGetString(moduleData->moduleNode, "directory");
	char *prefix    = sshsNodeGetString(moduleData->moduleNode, "prefix");

	char *filePath = getFullFilePath(moduleData, directory, prefix);
	free(directory);
	free(prefix);

	if (filePath == NULL) {
		// caerModuleLog() called inside getFullFilePath().
		return (false);
	}

	int fileFd = open(filePath, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP);
	if (fileFd < 0) {
		caerModuleLog(moduleData, CAER_LOG_CRITICAL,
			"Could not create or open output file '%s' for writing. Error: %d.", filePath, errno);
		free(filePath);

		return (false);
	}

	caerModuleLog(moduleData, CAER_LOG_INFO, "Opened output file '%s' successfully for writing.", filePath);
	free(filePath);

	if (!caerOutputCommonInit(moduleData, fileFd, NULL)) {
		close(fileFd);

		return (false);
	}

	return (true);
}
Пример #2
0
static bool caerInputUnixSocketInit(caerModuleData moduleData) {
	// First, always create all needed setting nodes, set their default values
	// and add their listeners.
	sshsNodeCreateString(moduleData->moduleNode, "socketPath", "/tmp/caer.sock", 2, PATH_MAX, SSHS_FLAGS_NORMAL,
		"Unix Socket path for reading input data.");

	// Open an existing Unix local socket at a known path, where we'll write to.
	int sockFd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sockFd < 0) {
		caerModuleLog(moduleData, CAER_LOG_CRITICAL, "Could not create local Unix socket. Error: %d.", errno);
		return (false);
	}

	struct sockaddr_un unixSocketAddr;
	memset(&unixSocketAddr, 0, sizeof(struct sockaddr_un));

	unixSocketAddr.sun_family = AF_UNIX;

	char *socketPath = sshsNodeGetString(moduleData->moduleNode, "socketPath");
	strncpy(unixSocketAddr.sun_path, socketPath, sizeof(unixSocketAddr.sun_path) - 1);
	unixSocketAddr.sun_path[sizeof(unixSocketAddr.sun_path) - 1] = '\0'; // Ensure NUL terminated string.
	free(socketPath);

	// Connect socket to above address.
	if (connect(sockFd, (struct sockaddr *) &unixSocketAddr, sizeof(struct sockaddr_un)) < 0) {
		close(sockFd);

		caerModuleLog(moduleData, CAER_LOG_CRITICAL, "Could not connect to local Unix socket. Error: %d.", errno);
		return (false);
	}

	if (!caerInputCommonInit(moduleData, sockFd, true, false)) {
		close(sockFd);
		return (false);
	}

	caerModuleLog(moduleData, CAER_LOG_INFO, "Local Unix socket ready at '%s'.", unixSocketAddr.sun_path);

	return (true);
}
Пример #3
0
static int caerConfigServerRunner(void *inPtr) {
	UNUSED_ARGUMENT(inPtr);

	// Get the right configuration node first.
	sshsNode serverNode = sshsGetNode(sshsGetGlobal(), "/server/");

	// Ensure default values are present.
	sshsNodePutStringIfAbsent(serverNode, "ipAddress", "127.0.0.1");
	sshsNodePutIntIfAbsent(serverNode, "portNumber", 4040);
	sshsNodePutShortIfAbsent(serverNode, "backlogSize", 5);
	sshsNodePutShortIfAbsent(serverNode, "concurrentConnections", 5);

	// Open a TCP server socket for configuration handling.
	// TCP chosen for reliability, which is more important here than speed.
	int configServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (configServerSocket < 0) {
		caerLog(CAER_LOG_CRITICAL, "Config Server", "Could not create server socket. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	// Make socket address reusable right away.
	socketReuseAddr(configServerSocket, true);

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

	configServerAddress.sin_family = AF_INET;
	configServerAddress.sin_port = htons(sshsNodeGetInt(serverNode, "portNumber"));
	char *ipAddress = sshsNodeGetString(serverNode, "ipAddress");
	inet_aton(ipAddress, &configServerAddress.sin_addr); // htonl() is implicit here.
	free(ipAddress);

	// Bind socket to above address.
	if (bind(configServerSocket, (struct sockaddr *) &configServerAddress, sizeof(struct sockaddr_in)) < 0) {
		caerLog(CAER_LOG_CRITICAL, "Config Server", "Could not bind server socket. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	// Listen to new connections on the socket.
	if (listen(configServerSocket, sshsNodeGetShort(serverNode, "backlogSize")) < 0) {
		caerLog(CAER_LOG_CRITICAL, "Config Server", "Could not listen on server socket. Error: %d.", errno);
		return (EXIT_FAILURE);
	}

	// Control message format: 1 byte ACTION, 1 byte TYPE, 2 bytes EXTRA_LEN,
	// 2 bytes NODE_LEN, 2 bytes KEY_LEN, 2 bytes VALUE_LEN, then up to 4086
	// bytes split between EXTRA, NODE, KEY, VALUE (with 4 bytes for NUL).
	// Basically: (EXTRA_LEN + NODE_LEN + KEY_LEN + VALUE_LEN) <= 4086.
	// EXTRA, NODE, KEY, VALUE have to be NUL terminated, and their length
	// must include the NUL termination byte.
	// This results in a maximum message size of 4096 bytes (4KB).
	uint8_t configServerBuffer[4096];

	caerLog(CAER_LOG_NOTICE, "Config Server", "Ready and listening on %s:%" PRIu16 ".",
		inet_ntoa(configServerAddress.sin_addr), ntohs(configServerAddress.sin_port));

	size_t connections = (size_t) sshsNodeGetShort(serverNode, "concurrentConnections") + 1;// +1 for listening socket.

	struct pollfd pollSockets[connections];

	// Initially ignore all pollfds, and react only to POLLIN events.
	for (size_t i = 0; i < connections; i++) {
		pollSockets[i].fd = -1;
		pollSockets[i].events = POLLIN;
	}

	// First pollfd is the listening socket, always.
	pollSockets[0].fd = configServerSocket;

	while (atomic_load_explicit(&configServerThread.running, memory_order_relaxed)) {
		int pollResult = poll(pollSockets, (nfds_t) connections, 1000);

		if (pollResult > 0) {
			// First let's check if there's a new connection waiting to be accepted.
			if ((pollSockets[0].revents & POLLIN) != 0) {
				int newClientSocket = accept(pollSockets[0].fd, NULL, NULL);

				if (newClientSocket >= 0) {
					// Put it in the list of watched fds if possible, or close.
					bool putInFDList = false;

					for (size_t i = 1; i < connections; i++) {
						if (pollSockets[i].fd == -1) {
							// Empty place in watch list, add this one.
							pollSockets[i].fd = newClientSocket;
							putInFDList = true;
							break;
						}
					}

					// No space for new connection, just close it (client will exit).
					if (!putInFDList) {
						close(newClientSocket);
						caerLog(CAER_LOG_DEBUG, "Config Server", "Rejected client (fd %d), queue full.",
							newClientSocket);
					}
					else {
						caerLog(CAER_LOG_DEBUG, "Config Server", "Accepted new connection from client (fd %d).",
							newClientSocket);
					}
				}
			}

			for (size_t i = 1; i < connections; i++) {
				// Work on existing connections, valid and with read events.
				if (pollSockets[i].fd != -1 && (pollSockets[i].revents & POLLIN) != 0) {
					// Accepted client connection, let's get all the data we need: first
					// the 10 byte header, and then whatever remains based on that.
					if (!recvUntilDone(pollSockets[i].fd, configServerBuffer, 10)) {
						// Closed on other side or error. Let's just close here too.
						close(pollSockets[i].fd);

						caerLog(CAER_LOG_DEBUG, "Config Server", "Disconnected client on recv (fd %d).",
							pollSockets[i].fd);
						pollSockets[i].fd = -1;

						continue;
					}

					// Decode header fields (all in little-endian).
					uint8_t action = configServerBuffer[0];
					uint8_t type = configServerBuffer[1];
					uint16_t extraLength = le16toh(*(uint16_t * )(configServerBuffer + 2));
					uint16_t nodeLength = le16toh(*(uint16_t * )(configServerBuffer + 4));
					uint16_t keyLength = le16toh(*(uint16_t * )(configServerBuffer + 6));
					uint16_t valueLength = le16toh(*(uint16_t * )(configServerBuffer + 8));

					// Total length to get for command.
					size_t readLength = (size_t) (extraLength + nodeLength + keyLength + valueLength);

					if (!recvUntilDone(pollSockets[i].fd, configServerBuffer + 10, readLength)) {
						// Closed on other side or error. Let's just close here too.
						close(pollSockets[i].fd);

						caerLog(CAER_LOG_DEBUG, "Config Server", "Disconnected client on recv (fd %d).",
							pollSockets[i].fd);
						pollSockets[i].fd = -1;

						continue;
					}

					// Now we have everything. The header fields are already
					// fully decoded: handle request (and send back data eventually).
					caerConfigServerHandleRequest(pollSockets[i].fd, action, type, configServerBuffer + 10, extraLength,
						configServerBuffer + 10 + extraLength, nodeLength,
						configServerBuffer + 10 + extraLength + nodeLength, keyLength,
						configServerBuffer + 10 + extraLength + nodeLength + keyLength, valueLength);
				}
			}
		}
		else if (pollResult < 0) {
			caerLog(CAER_LOG_ALERT, "Config Server", "poll() failed. Error: %d.", errno);
		}
		// pollResult == 0 just means nothing to do (timeout reached).
	}

	// Shutdown!
	close(configServerSocket);

	return (EXIT_SUCCESS);
}
Пример #4
0
static void handleNewServerConnections(outputCommonState state) {
	// First let's see if any new connections are waiting on the listening
	// socket to be accepted. This returns right away (non-blocking).
	socklen_t clientAddrLength = sizeof(struct sockaddr_in);
	struct sockaddr_in clientAddr;
	memset(&clientAddr, 0, clientAddrLength);

	int acceptResult = accept(state->fileDescriptors->serverFd, (struct sockaddr *) &clientAddr, &clientAddrLength);
	if (acceptResult < 0) {
		if (errno != EAGAIN && errno != EWOULDBLOCK) {
			// Only log real failure. EAGAIN/EWOULDBLOCK just means no
			// connections are present for non-blocking accept() right now.
			caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString,
				"TCP server accept() failed. Error: %d.", errno);
		}

		return;
	}

	// New connection present!
	// Put it in the list of FDs and send header, if there is space left, or close.
	for (size_t i = 0; i < state->fileDescriptors->fdsSize; i++) {
		if (state->fileDescriptors->fds[i] == -1) {
			caerLog(CAER_LOG_DEBUG, state->parentModule->moduleSubSystemString,
				"Accepted new TCP connection from client (fd %d).", acceptResult);

			// Commit current buffer, so that for the new clients, it's empty, and they
			// don't get packets and data that are possibly cut in the middle.
			commitOutputBuffer(state);

			// Empty place in FD list, add this one.
			state->fileDescriptors->fds[i] = acceptResult;

			// Successfully connected, send header to client.
			sendNetworkHeader(state, &state->fileDescriptors->fds[i]);

			// Add client IP to list. This is a comma separated string.
			char *connectedClientsStr = sshsNodeGetString(state->parentModule->moduleNode, "connectedClients");

			size_t newConnectedClientStrLength = strlen(connectedClientsStr) + 1 + INET_ADDRSTRLEN + 1;
			char *newConnectedClientsStr = realloc(connectedClientsStr, newConnectedClientStrLength);
			if (newConnectedClientsStr == NULL) {
				free(connectedClientsStr);

				caerLog(CAER_LOG_ERROR, state->parentModule->moduleSubSystemString,
					"Failed to update connectedClients information.");
				return;
			}

			const char *clientAddrStr = inet_ntop(AF_INET, &clientAddr.sin_addr, (char[INET_ADDRSTRLEN] ) { 0x00 },
				INET_ADDRSTRLEN);

			if (!caerStrEquals(newConnectedClientsStr, "")) {
				// Only prepend comma if the string wasn't empty before.
				strncat(newConnectedClientsStr, ",", 1);
			}
			strncat(newConnectedClientsStr, clientAddrStr, INET_ADDRSTRLEN);

			sshsNodePutString(state->parentModule->moduleNode, "connectedClients", newConnectedClientsStr);

			free(newConnectedClientsStr);

			return;
		}
Пример #5
0
static bool caerOutputUnixSocketServerInit(caerModuleData moduleData) {
	// First, always create all needed setting nodes, set their default values
	// and add their listeners.
	sshsNodeCreateString(moduleData->moduleNode, "socketPath", "/tmp/caer.sock", 2, PATH_MAX, SSHS_FLAGS_NORMAL,
		"Unix Socket path for writing output data (server mode, create new socket).");
	sshsNodeCreateInt(
		moduleData->moduleNode, "backlogSize", 5, 1, 32, SSHS_FLAGS_NORMAL, "Maximum number of pending connections.");
	sshsNodeCreateInt(moduleData->moduleNode, "concurrentConnections", 10, 1, 128, SSHS_FLAGS_NORMAL,
		"Maximum number of concurrent active connections.");

	// Allocate memory.
	size_t numClients         = (size_t) sshsNodeGetInt(moduleData->moduleNode, "concurrentConnections");
	outputCommonNetIO streams = malloc(sizeof(*streams) + (numClients * sizeof(uv_stream_t *)));
	if (streams == NULL) {
		caerModuleLog(moduleData, CAER_LOG_ERROR, "Failed to allocate memory for streams structure.");
		return (false);
	}

	streams->server = malloc(sizeof(uv_pipe_t));
	if (streams->server == NULL) {
		free(streams);

		caerModuleLog(moduleData, CAER_LOG_ERROR, "Failed to allocate memory for network server.");
		return (false);
	}

	// Initialize common info.
	streams->isTCP         = false;
	streams->isUDP         = false;
	streams->isPipe        = true;
	streams->activeClients = 0;
	streams->clientsSize   = numClients;
	for (size_t i = 0; i < streams->clientsSize; i++) {
		streams->clients[i] = NULL;
	}

	// Remember address.
	streams->address = sshsNodeGetString(moduleData->moduleNode, "socketPath");

	streams->server->data = streams;

	// Initialize loop and network handles.
	int retVal = uv_loop_init(&streams->loop);
	UV_RET_CHECK(retVal, moduleData->moduleSubSystemString, "uv_loop_init", free(streams->server);
				 free(streams->address); free(streams); return (false));

	retVal = uv_pipe_init(&streams->loop, (uv_pipe_t *) streams->server, false);
	UV_RET_CHECK(retVal, moduleData->moduleSubSystemString, "uv_pipe_init", uv_loop_close(&streams->loop);
				 free(streams->server); free(streams->address); free(streams); return (false));

	retVal = uv_pipe_bind((uv_pipe_t *) streams->server, streams->address);
	UV_RET_CHECK(retVal, moduleData->moduleSubSystemString, "uv_pipe_bind", libuvCloseLoopHandles(&streams->loop);
				 uv_loop_close(&streams->loop); free(streams->address); free(streams); return (false));

	retVal = uv_listen(
		streams->server, sshsNodeGetInt(moduleData->moduleNode, "backlogSize"), &caerOutputCommonOnServerConnection);
	UV_RET_CHECK(retVal, moduleData->moduleSubSystemString, "uv_listen", libuvCloseLoopHandles(&streams->loop);
				 uv_loop_close(&streams->loop); free(streams->address); free(streams); return (false));

	// Start.
	if (!caerOutputCommonInit(moduleData, -1, streams)) {
		libuvCloseLoopHandles(&streams->loop);
		uv_loop_close(&streams->loop);
		free(streams->address);
		free(streams);

		return (false);
	}

	return (true);
}
Пример #6
0
static bool caerOutputUnixSocketServerInit(caerModuleData moduleData) {
	// First, always create all needed setting nodes, set their default values
	// and add their listeners.
	sshsNodePutStringIfAbsent(moduleData->moduleNode, "socketPath", "/tmp/caer.sock");
	sshsNodePutShortIfAbsent(moduleData->moduleNode, "backlogSize", 5);
	sshsNodePutShortIfAbsent(moduleData->moduleNode, "concurrentConnections", 10);

	// Open a Unix local socket on a known path, to be accessed by other processes (server-like mode).
	int serverSockFd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (serverSockFd < 0) {
		caerLog(CAER_LOG_CRITICAL, moduleData->moduleSubSystemString, "Could not create local Unix socket. Error: %d.",
		errno);
		return (false);
	}

	struct sockaddr_un unixSocketAddr;
	memset(&unixSocketAddr, 0, sizeof(struct sockaddr_un));

	unixSocketAddr.sun_family = AF_UNIX;

	char *socketPath = sshsNodeGetString(moduleData->moduleNode, "socketPath");
	strncpy(unixSocketAddr.sun_path, socketPath, sizeof(unixSocketAddr.sun_path) - 1);
	unixSocketAddr.sun_path[sizeof(unixSocketAddr.sun_path) - 1] = '\0'; // Ensure NUL terminated string.
	free(socketPath);

	// Bind socket to above address.
	if (bind(serverSockFd, (struct sockaddr *) &unixSocketAddr, sizeof(struct sockaddr_un)) < 0) {
		close(serverSockFd);

		caerLog(CAER_LOG_CRITICAL, moduleData->moduleSubSystemString, "Could not bind local Unix socket. Error: %d.",
		errno);
		return (false);
	}

	// Listen to new connections on the socket.
	if (listen(serverSockFd, sshsNodeGetShort(moduleData->moduleNode, "backlogSize")) < 0) {
		close(serverSockFd);

		caerLog(CAER_LOG_CRITICAL, moduleData->moduleSubSystemString,
			"Could not listen on local Unix socket. Error: %d.", errno);
		return (false);
	}

	outputCommonFDs fileDescriptors = caerOutputCommonAllocateFdArray(
		(size_t) sshsNodeGetShort(moduleData->moduleNode, "concurrentConnections"));
	if (fileDescriptors == NULL) {
		close(serverSockFd);

		caerLog(CAER_LOG_CRITICAL, moduleData->moduleSubSystemString,
			"Unable to allocate memory for file descriptors.");
		return (false);
	}

	fileDescriptors->serverFd = serverSockFd;

	if (!caerOutputCommonInit(moduleData, fileDescriptors, true, false)) {
		close(serverSockFd);
		free(fileDescriptors);

		return (false);
	}

	caerLog(CAER_LOG_INFO, moduleData->moduleSubSystemString, "Local Unix socket ready at '%s'.",
		unixSocketAddr.sun_path);

	return (true);
}
Пример #7
0
static bool caerInputDVS128Init(caerModuleData moduleData) {
	caerLog(CAER_LOG_DEBUG, moduleData->moduleSubSystemString, "Initializing module ...");

	// USB port/bus/SN settings/restrictions.
	// These can be used to force connection to one specific device at startup.
	sshsNodePutShortIfAbsent(moduleData->moduleNode, "BusNumber", 0);
	sshsNodePutShortIfAbsent(moduleData->moduleNode, "DevAddress", 0);
	sshsNodePutStringIfAbsent(moduleData->moduleNode, "SerialNumber", "");

	// Add auto-restart setting.
	sshsNodePutBoolIfAbsent(moduleData->moduleNode, "Auto-Restart", true);

	// 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(moduleData->moduleID, CAER_DEVICE_DVS128,
		U8T(sshsNodeGetShort(moduleData->moduleNode, "BusNumber")),
		U8T(sshsNodeGetShort(moduleData->moduleNode, "DevAddress")), serialNumber);
	free(serialNumber);

	if (moduleData->moduleState == NULL) {
		// Failed to open device.
		return (false);
	}

	// Put global source information into SSHS.
	struct caer_dvs128_info devInfo = caerDVS128InfoGet(moduleData->moduleState);

	sshsNode sourceInfoNode = sshsGetRelativeNode(moduleData->moduleNode, "sourceInfo/");

	sshsNodePutShort(sourceInfoNode, "logicVersion", devInfo.logicVersion);
	sshsNodePutBool(sourceInfoNode, "deviceIsMaster", devInfo.deviceIsMaster);

	sshsNodePutShort(sourceInfoNode, "dvsSizeX", devInfo.dvsSizeX);
	sshsNodePutShort(sourceInfoNode, "dvsSizeY", devInfo.dvsSizeY);

	// Put source information for "virtual" APS frame that can be used to display and debug filter information.
	sshsNodePutShort(sourceInfoNode, "apsSizeX", devInfo.dvsSizeX);
	sshsNodePutShort(sourceInfoNode, "apsSizeY", devInfo.dvsSizeY);

	caerModuleSetSubSystemString(moduleData, devInfo.deviceString);

	// 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.
	createDefaultConfiguration(moduleData);
	sendDefaultConfiguration(moduleData);

	// Start data acquisition.
	bool ret = caerDeviceDataStart(moduleData->moduleState, &mainloopDataNotifyIncrease, &mainloopDataNotifyDecrease,
		caerMainloopGetReference(), &moduleShutdownNotify, moduleData->moduleNode);

	if (!ret) {
		// Failed to start data acquisition, close device and exit.
		caerDeviceClose((caerDeviceHandle *) &moduleData->moduleState);

		return (false);
	}

	return (true);
}
Пример #8
0
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);
}
Пример #9
0
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);
}