void LidarProcessOctree::subdivide(LidarProcessOctree::Node& node)
	{
	{
	#if ALLOW_THREADING
	Threads::Mutex::Lock lruLock(lruMutex);
	#endif
	++numSubdivideCalls;
	}
	
	#if ALLOW_THREADING
	Threads::Mutex::Lock nodeLock(node.mutex);
	#endif
	
	/* Bail out if the node's children have magically appeared since the last check: */
	if(node.children!=0)
		return;
	
	/* Check if the node cache is full: */
	{
	#if ALLOW_THREADING
	Threads::Mutex::Lock lruLock(lruMutex);
	#endif
	if(numCachedNodes+8>cacheSize)
		{
		/* Find an unused leaf node parent and remove its children: */
		Node* coarsenNode;
		#if ALLOW_THREADING
		for(coarsenNode=lruHead;coarsenNode!=0;coarsenNode=coarsenNode->lruSucc)
			{
			/* Check if the leaf parent is currently unused: */
			coarsenNode->mutex.lock();
			if(coarsenNode->processCounter==0)
				break;
			coarsenNode->mutex.unlock();
			}
		#else
		for(coarsenNode=lruHead;coarsenNode!=0&&coarsenNode->processCounter!=0;coarsenNode=coarsenNode->lruSucc)
			;
		#endif
		
		/* Remove the found node's children: */
		delete[] coarsenNode->children;
		coarsenNode->children=0;
		
		#if ALLOW_THREADING
		coarsenNode->mutex.unlock();
		#endif
		
		/* Remove the found node from the lru list: */
		if(coarsenNode->lruPred!=0)
			coarsenNode->lruPred->lruSucc=coarsenNode->lruSucc;
		else
			lruHead=coarsenNode->lruSucc;
		if(coarsenNode->lruSucc!=0)
			coarsenNode->lruSucc->lruPred=coarsenNode->lruPred;
		else
			lruTail=coarsenNode->lruPred;
		coarsenNode->lruPred=0;
		coarsenNode->lruSucc=0;
		
		/* Update the node cache: */
		numCachedNodes-=8;
		
		/* Check if the found node's parent is now a leaf parent node: */
		Node* parent=coarsenNode->parent;
		if(parent!=0)
			{
			/* Check if all children of the parent are leaves: */
			bool leafParent=true;
			for(int childIndex=0;childIndex<8&&leafParent;++childIndex)
				leafParent=parent->children[childIndex].children==0;
			
			if(leafParent)
				{
				/* Add the parent to the end of the leaf parent node list: */
				parent->lruPred=lruTail;
				parent->lruSucc=0;
				if(lruTail!=0)
					lruTail->lruSucc=parent;
				else
					lruHead=parent;
				lruTail=parent;
				}
			}
		}
	
	/* Check if the node's parent was a leaf parent: */
	Node* parent=node.parent;
	if(parent!=0&&(parent->lruPred!=0||parent->lruSucc!=0||lruHead==parent))
		{
		/* Remove the node's parent from the leaf parent node list: */
		if(parent->lruPred!=0)
			parent->lruPred->lruSucc=parent->lruSucc;
		else
			lruHead=parent->lruSucc;
		if(parent->lruSucc!=0)
			parent->lruSucc->lruPred=parent->lruPred;
		else
			lruTail=parent->lruPred;
		parent->lruPred=0;
		parent->lruSucc=0;
		}
	
	/* Add the node to the leaf parent node list: */
	node.lruPred=lruTail;
	node.lruSucc=0;
	if(lruTail!=0)
		lruTail->lruSucc=&node;
	else
		lruHead=&node;
	lruTail=&node;
	
	/* Update the node cache: */
	numCachedNodes+=8U;
	}
	
	/* Create and load the node's children: */
	{
	#if ALLOW_THREADING
	Threads::Mutex::Lock fileLock(fileMutex);
	#endif
	Node* children=new Node[8];
	indexFile.setReadPosAbs(node.childrenOffset);
	for(int childIndex=0;childIndex<8;++childIndex)
		{
		Node& child=children[childIndex];
		
		/* Read the child node's structure: */
		LidarOctreeFileNode ofn;
		ofn.read(indexFile);
		child.parent=&node;
		child.childrenOffset=ofn.childrenOffset;
		child.domain=Cube(node.domain,childIndex);
		child.numPoints=ofn.numPoints;
		child.dataOffset=ofn.dataOffset;
		child.detailSize=ofn.detailSize;
		
		if(child.numPoints>0)
			{
			/* Load the child node's points: */
			child.points=new LidarPoint[maxNumPointsPerNode]; // Always allocate maximum to prevent memory fragmentation
			pointsFile.setReadPosAbs(LidarDataFileHeader::getFileSize()+pointsRecordSize*child.dataOffset);
			pointsFile.read(child.points,child.numPoints);
			}
		
		++numLoadedNodes;
		}
	
	/* Install the node's children array: */
	node.children=children;
	}
	}
Пример #2
0
void _begin() {
	#if !defined(MY_DISABLED_SERIAL)
	    hwInit();
	#endif

	// Call before() in sketch (if it exists)
	if (before) 
		before();

	debug(PSTR("Starting " MY_NODE_TYPE " (" MY_CAPABILITIES ", " LIBRARY_VERSION ")\n"));

	signerInit();

	#if defined(MY_RADIO_FEATURE)
		_failedTransmissions = 0;

		// Setup radio
		if (!transportInit()) {
			debug(PSTR("Radio init failed. Check wiring.\n"));
			// Nothing more we can do
			_infiniteLoop();
		} else {
			debug(PSTR("Radio init successful.\n"));
		}
	#endif

	#if defined(MY_GATEWAY_FEATURE)
		#if defined(MY_INCLUSION_BUTTON_FEATURE)
	    	inclusionInit();
		#endif

	    // initialize the transport driver
		if (!gatewayTransportInit()) {
			debug(PSTR("Transport driver init fail\n"));
			// Nothing more we can do
			_infiniteLoop();
		}

	#endif


	#if defined(MY_LEDS_BLINKING_FEATURE)
		ledsInit();
	#endif

	// Read latest received controller configuration from EEPROM
	hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig));
	if (_cc.isMetric == 0xff) {
		// Eeprom empty, set default to metric
		_cc.isMetric = 0x01;
	}

	#if defined(MY_GATEWAY_FEATURE)
		// Set configuration for gateway
		_nc.parentNodeId = GATEWAY_ADDRESS;
		_nc.distance = 0;
		_nc.nodeId = GATEWAY_ADDRESS;
	#elif defined(MY_RADIO_FEATURE)
		// Read settings from eeprom
		hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig));
		#ifdef MY_OTA_FIRMWARE_FEATURE
			// Read firmware config from EEPROM, i.e. type, version, CRC, blocks
			hwReadConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
		#endif

		_autoFindParent = MY_PARENT_NODE_ID == AUTO;
		if (!_autoFindParent) {
			_nc.parentNodeId = MY_PARENT_NODE_ID;
			// Save static parent id in eeprom (used by bootloader)
			hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID);
			// We don't actually know the distance to gw here. Let's pretend it is 1.
			// If the current node is also repeater, be aware of this.
			_nc.distance = 1;
		} else if (!isValidParent(_nc.parentNodeId)) {
			// Auto find parent, but parent in eeprom is invalid. Try find one.
			transportFindParentNode();
		}

		if (MY_NODE_ID != AUTO) {
			// Set static id
			_nc.nodeId = MY_NODE_ID;
			// Save static id in eeprom
			hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID);
		} else if (_nc.nodeId == AUTO && isValidParent(_nc.parentNodeId)) {
			// Try to fetch node-id from gateway
			transportRequestNodeId();
		}
	#endif

#ifdef MY_NODE_LOCK_FEATURE
	// Check if node has been locked down
	if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) {
		// Node is locked, check if unlock pin is asserted, else hang the node
		pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP);
		// Make a short delay so we are sure any large external nets are fully pulled
		unsigned long enter = hwMillis();
		while (hwMillis() - enter < 2);
		if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) {
			// Pin is grounded, reset lock counter
			hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX);
			// Disable pullup
			pinMode(MY_NODE_UNLOCK_PIN, INPUT);
			debug(PSTR("Node is unlocked.\n"));
		} else {
			// Disable pullup
			pinMode(MY_NODE_UNLOCK_PIN, INPUT);
			nodeLock("LDB"); //Locked during boot
		}
	} else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) {
		// Reset walue
		hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX);
	}
#endif

	// Call sketch setup
	if (setup)
		setup();


	#if defined(MY_RADIO_FEATURE)
		transportPresentNode();
	#endif
	if (presentation)
		presentation();

	debug(PSTR("Init complete, id=%d, parent=%d, distance=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance);
}