Example #1
0
bool
DriverInstall()
{
	CONFIG_DATA *cd = GetConfigData();

	// Open the service control manager
	SC_HANDLE hScm = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
	if (!hScm) return false;

	// Create the driver service
	bool rv = false;
	WCHAR szDriverPath[MAX_PATH+7] = { '\0' };
	wstrlprintf(szDriverPath, sizeof(szDriverPath), L"%ls", cd->szProcFilterDriver);
	SC_HANDLE hDriverService = CreateServiceW(hScm, PROCFILTER_DRIVER_SERVICE_NAME, PROCFILTER_DRIVER_SERVICE_DISPLAY_NAME, SERVICE_START | SERVICE_STOP | DELETE,
										SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, szDriverPath, 0, 0, 0, 0, 0);

	// Was the service created? Or does it already exist?
	if (hDriverService) {
		rv = true;
		CloseServiceHandle(hDriverService);
	} else if (GetLastError() == ERROR_SERVICE_EXISTS) {
		rv = true;
	}

	CloseServiceHandle(hScm);

	return rv;
}
QStringList ConfigGroundVehicleWidget::getChannelDescriptions()
{
    int i;
    QStringList channelDesc;

    // init a channel_numelem list of channel desc defaults
    for (i=0; i < (int)(ConfigGroundVehicleWidget::CHANNEL_NUMELEM); i++)
    {
        channelDesc.append(QString("-"));
    }

    // get the gui config data
    GUIConfigDataUnion configData = GetConfigData();

    if (configData.ground.GroundVehicleSteering1 > 0)
        channelDesc[configData.ground.GroundVehicleSteering1-1] = QString("GroundSteering1");
    if (configData.ground.GroundVehicleSteering2 > 0)
        channelDesc[configData.ground.GroundVehicleSteering2-1] = QString("GroundSteering2");
    if (configData.ground.GroundVehicleThrottle1 > 0)
        channelDesc[configData.ground.GroundVehicleThrottle1-1] = QString("GroundThrottle1");
    if (configData.ground.GroundVehicleThrottle2 > 0)
        channelDesc[configData.ground.GroundVehicleThrottle2-1] = QString("GroundThrottle2");

    return channelDesc;
}
Example #3
0
void GetConfigUART(lua_State* L, int index, SerialConfig* serialConfig) {
    if (!lua_isnil(L, index)) {
        if (lua_istable(L, index)) {
            lua_getfield(L, index, "baudrate");
            GetConfigBaudrate(L, -1, &(serialConfig->baudrate));
            lua_pop(L, 1);

            lua_getfield(L, index, "parity");
            GetConfigParity(L, -1, &(serialConfig->parity));
            lua_pop(L, 1);

            lua_getfield(L, index, "data");
            GetConfigData(L, -1, &(serialConfig->data));
            lua_pop(L, 1);

            lua_getfield(L, index, "stop");
            GetConfigStop(L, -1, &(serialConfig->stop));
            lua_pop(L, 1);

            lua_getfield(L, index, "flowcontrol");
            GetConfigFlowControl(L, -1, &(serialConfig->flowControl));
            lua_pop(L, 1);

            lua_getfield(L, index, "timeout");
            GetConfigTimeout(L, -1, &(serialConfig->timeout));
            lua_pop(L, 1);

            lua_getfield(L, index, "retry");
            GetConfigRetry(L, -1, &(serialConfig->retry));
            lua_pop(L, 1);
        } else {
            luaL_error(L, "'cfg' should be a table");
        }
    }
}
/**
 Helper function: setup motors. Takes a list of channel names in input.
 */
void ConfigMultiRotorWidget::setupMotors(QList<QString> motorList)
{
    QList<QComboBox*> mmList;
    mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3
           << m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6
           << m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8;

    GUIConfigDataUnion configData = GetConfigData();
    ResetActuators(&configData);

    int index;
    foreach (QString motor, motorList) {

        index = mmList.takeFirst()->currentIndex();

        if (motor == QString("VTOLMotorN"))
            configData.multi.VTOLMotorN = index;
        else if (motor == QString("VTOLMotorNE"))
            configData.multi.VTOLMotorNE = index;
        else if (motor == QString("VTOLMotorE"))
            configData.multi.VTOLMotorE = index;
        else if (motor == QString("VTOLMotorSE"))
            configData.multi.VTOLMotorSE = index;
        else if (motor == QString( "VTOLMotorS"))
            configData.multi.VTOLMotorS = index;
        else if (motor == QString( "VTOLMotorSW"))
            configData.multi.VTOLMotorSW = index;
        else if (motor == QString( "VTOLMotorW"))
            configData.multi.VTOLMotorW = index;
        else if (motor == QString( "VTOLMotorNW"))
            configData.multi.VTOLMotorNW = index;
    }
bool InitializeFlowInterface(Controller *me)
{
	RegistrationData regData;

	GetConfigData(&regData);

	if (InitialiseLibFlowMessaging((const char *)regData.url, (const char *)regData.key,(const char *)regData.secret))
	{
		if (RegisterDevice(regData.deviceType,
						regData.deviceMACAddress,
						regData.deviceSerialNumber,
						DEVICE_SOFTWARE_VERSION,
						regData.deviceName,
						regData.devRegKey))
		{
			if (GetUserId(me->userId))
			{
				GetDeviceId(SENSOR_DEVICE_TYPE, me->userId, &me->sensorConfig.sensorId);
				GetDeviceId(ACTUATOR_DEVICE_TYPE, me->userId, &me->actuatorConfig.actuatorId);
				printf("Flow Interface initialized successfully\n");
				return true;
			}
		}
	}

	printf("Flow Interface initialization failed\n");
	return false;
}
QStringList ConfigMultiRotorWidget::getChannelDescriptions()
{
    QStringList channelDesc;

    // init a channel_numelem list of channel desc defaults
    for (int i=0; i < (int)(ConfigMultiRotorWidget::CHANNEL_NUMELEM); i++)
    {
        channelDesc.append(QString("-"));
    }

    // get the gui config data
    GUIConfigDataUnion configData = GetConfigData();
    multiGUISettingsStruct multi = configData.multi;

    if (multi.VTOLMotorN > 0 && multi.VTOLMotorN <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorN-1] = QString("VTOLMotorN");
    if (multi.VTOLMotorNE > 0 && multi.VTOLMotorNE <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorNE-1] = QString("VTOLMotorNE");
    if (multi.VTOLMotorNW > 0 && multi.VTOLMotorNW <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorNW-1] = QString("VTOLMotorNW");
    if (multi.VTOLMotorS > 0 && multi.VTOLMotorS <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorS-1] = QString("VTOLMotorS");
    if (multi.VTOLMotorSE > 0 && multi.VTOLMotorSE <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorSE-1] = QString("VTOLMotorSE");
    if (multi.VTOLMotorSW > 0 && multi.VTOLMotorSW <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorSW-1] = QString("VTOLMotorSW");
    if (multi.VTOLMotorW > 0 && multi.VTOLMotorW <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorW-1] = QString("VTOLMotorW");
    if (multi.VTOLMotorE > 0 && multi.VTOLMotorE <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.VTOLMotorE-1] = QString("VTOLMotorE");
    if (multi.TRIYaw > 0 && multi.TRIYaw <= ConfigMultiRotorWidget::CHANNEL_NUMELEM)
        channelDesc[multi.TRIYaw-1] = QString("Tri-Yaw");

    return channelDesc;
}
/**
 Setup steerable ground vehicle.
 
 Returns False if impossible to create the mixer.
 */
bool ConfigGroundVehicleWidget::setupGroundVehicleCar(SystemSettings::AirframeTypeOptions airframeType)
{
    // Check coherence:
	//Show any config errors in GUI
    if (throwConfigError(airframeType)) {
		return false;
	}

    // Now setup the channels:
    GUIConfigDataUnion config = GetConfigData();
    ResetActuators(&config);
	
    config.ground.GroundVehicleThrottle1 = m_aircraft->gvMotor1ChannelBox->currentIndex();
    config.ground.GroundVehicleThrottle2 = m_aircraft->gvMotor2ChannelBox->currentIndex();
    config.ground.GroundVehicleSteering1 = m_aircraft->gvSteering1ChannelBox->currentIndex();
    config.ground.GroundVehicleSteering2 = m_aircraft->gvSteering2ChannelBox->currentIndex();

    SetConfigData(config);

    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    Q_ASSERT(mixerSettings);
    resetMixers(mixerSettings);

    int channel = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_SERVO);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW, 127);

    channel = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_SERVO);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW, -127);

    channel = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_MOTOR);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_THROTTLECURVE1, 127);

    channel = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
    setMixerType(mixerSettings,channel, MixerSettings::MIXER1TYPE_MOTOR);
    setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_THROTTLECURVE2, 127);

	//Output success message
    m_aircraft->gvStatusLabel->setText("Mixer generated");
	
    return true;
}
/**
 Virtual function to refresh the UI widget values
 */
void ConfigGroundVehicleWidget::refreshAirframeWidgetsValues(SystemSettings::AirframeTypeOptions frameType)
{
    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    Q_ASSERT(mixerSettings);

    GUIConfigDataUnion config = GetConfigData();

	//THIS SECTION STILL NEEDS WORK. FOR THE MOMENT, USE THE FIXED-WING ONBOARD SETTING IN ORDER TO MINIMIZE CHANCES OF BOLLOXING REAL CODE
	// Retrieve channel setup values
    setComboCurrentIndex(m_aircraft->gvMotor1ChannelBox, config.ground.GroundVehicleThrottle1);
    setComboCurrentIndex(m_aircraft->gvMotor2ChannelBox, config.ground.GroundVehicleThrottle2);
    setComboCurrentIndex(m_aircraft->gvSteering1ChannelBox, config.ground.GroundVehicleSteering1);
    setComboCurrentIndex(m_aircraft->gvSteering2ChannelBox, config.ground.GroundVehicleSteering2);

    if (frameType == SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEDIFFERENTIAL) {
		//CURRENTLY BROKEN UNTIL WE DECIDE HOW DIFFERENTIAL SHOULD BEHAVE
		// If the vehicle type is "differential", restore the slider setting
		
		// Find the channel number for Motor1 
        int channel = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
        if (channel > -1) { // If for some reason the actuators were incoherent, we might fail here, hence the check.

            m_aircraft->differentialSteeringSlider1->setValue(getMixerVectorValue(mixerSettings,channel,MixerSettings::MIXER1VECTOR_ROLL)*100);
            m_aircraft->differentialSteeringSlider2->setValue(getMixerVectorValue(mixerSettings,channel,MixerSettings::MIXER1VECTOR_PITCH)*100);
		}
	}
    if (frameType == SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEMOTORCYCLE) {
		//CURRENTLY BROKEN UNTIL WE DECIDE HOW MOTORCYCLE SHOULD BEHAVE
//		obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
//		Q_ASSERT(obj);
//		int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
//		if (chMixerNumber >=0) {
//			field = obj->getField(mixerVectors.at(chMixerNumber));
//			int ti = field->getElementNames().indexOf("Yaw");
//			m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
//			
//			ti = field->getElementNames().indexOf("Pitch");
//			m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
//		}
	}
}
Example #9
0
DWORD
WINAPI
ep_DriverService(void *arg)
{
	const CONFIG_DATA *cd = GetConfigData();

	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

	// Build the threadpool
	POOL_DATA pd;
	ZeroMemory(&pd, sizeof(POOL_DATA));
	pd.hSharedDriverHandle = g_hDriver;
	const DWORD dwNumChannels = NUM_EVENTTYPES-1; // -1 to ignore EVENT_NONE
	THREADPOOL *tp = ThreadPoolAlloc(cd->dThreadPoolSize, dwNumChannels, PfWorkerInit, PfWorkerWork, PfWorkerDestroy, &pd, sizeof(WORKER_DATA), THREAD_PRIORITY_NORMAL);
	if (!tp) Die("Unable to allocate threadpool");

	// Create the read file event for use with overlapped I/O
	HANDLE hReadFileEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (hReadFileEvent == NULL) Die("Unable to create read file event");

	// Allocate memory for the buffer to be read from the kernel
	PROCFILTER_REQUEST *req = (PROCFILTER_REQUEST*)_malloca(PROCFILTER_REQUEST_SIZE);
	while (true) {
		if (WaitForSingleObject(g_hStopTheadEvent, 0) == WAIT_OBJECT_0) break;

		// Read request from driver using synch/asynch calls according to https://support.microsoft.com/en-us/kb/156932
		DWORD dwBytesRead = 0;
		OVERLAPPED overlapped;
		ZeroMemory(&overlapped, sizeof(OVERLAPPED));
		ResetEvent(hReadFileEvent);
		overlapped.hEvent = hReadFileEvent;
		BOOL rc = ReadFile(g_hDriver, req, PROCFILTER_REQUEST_SIZE, &dwBytesRead, &overlapped);
		DWORD dwErrorCode = GetLastError();
		if (rc) {
			// Successfully completed a synchronous read, do nothing
		} else if (dwErrorCode == ERROR_IO_PENDING) {
			// Successfully completed an asynchronous read, so wait for it
			DWORD dwNumberOfBytesTransferred = 0;
			if (!GetOverlappedResult(g_hDriver, &overlapped, &dwNumberOfBytesTransferred, TRUE)) {
				dwErrorCode = GetLastError();
				if (dwErrorCode == ERROR_OPERATION_ABORTED || dwErrorCode == ERROR_INVALID_HANDLE) break;
				// Cancel the pending IO to ensure the IO operation does not complete after this function ends
				// and the result is stored to an invalid location
				CancelIo(g_hDriver);
				Die("GetOverlappedResult() failure in reader: %d", dwErrorCode);
			}
			dwErrorCode = GetLastError();
			dwBytesRead = dwNumberOfBytesTransferred;
		} else if (dwErrorCode == ERROR_OPERATION_ABORTED || dwErrorCode == ERROR_INVALID_HANDLE) {
			break;
		} else {
			Die("Unable to read data from driver: %d / %ls", dwErrorCode, ErrorText(dwErrorCode));
		}
		LogDebugFmt("Read event from driver: PID:%u Event:%u", req->dwProcessId, req->dwEventType);
		ULONG64 ulStartPerformanceCount = GetPerformanceCount();
		
		// Validate the size of data read
		if (dwBytesRead < sizeof(PROCFILTER_REQUEST) || dwBytesRead > PROCFILTER_REQUEST_SIZE) {
			Die("Read invalid size from driver device: %u < %u || %u > %u  ReadFile:%hs ErrorCode:%d",
				dwBytesRead, sizeof(PROCFILTER_REQUEST), dwBytesRead, PROCFILTER_REQUEST_SIZE, rc ? "TRUE" : "FALSE", dwErrorCode);
		}
		if (dwBytesRead != req->dwRequestSize) {
			Die("Read partial packet from driver device: Read:%u PacketSize:%u", dwBytesRead, req->dwRequestSize);
		}
		
		// Post a copy of the retrieved data to a worker thread
		LogDebug("Posting work task to worker");
		// Allocate memory for the task data, the structure of which includes only the header portion of the procfilter request,
		// so allocate only the exact size needed
		WORKER_TASK_DATA *wtd = (WORKER_TASK_DATA*)malloc(sizeof(WORKER_TASK_DATA) + (dwBytesRead - sizeof(PROCFILTER_REQUEST)));
		if (!wtd) Die("Memory allocation failure for ProcFilter request");
		memcpy(&wtd->peProcFilterRequest, req, dwBytesRead);
		wtd->ulStartPerformanceCount = ulStartPerformanceCount;
		LogDebugFmt("Posting to threadpool: PID:%u Event:%u", req->dwProcessId, req->dwEventType);
		if (ThreadPoolPost(tp, req->dwEventType, false, g_hStopTheadEvent, wtd)) {
			LogDebug("Posted work task to worker");
		} else {
			LogDebugFmt("Failed to post task to worker");
			free(wtd);
		}
	}

	_freea(req);

	ThreadPoolFree(tp);

	CloseHandle(hReadFileEvent);
	
	// Driver closing is done here since this thread could terminate due to an error situation
	// and if closing were done elsewhere (such as service exit) the driver device would be kept open, consequently
	// blocking process creation events until service shutdown
	CloseHandle(g_hDriver);
	g_hDriver = INVALID_HANDLE_VALUE;

	return 0;
}
Example #10
0
void
LoadKernelDriver()
{
	CONFIG_DATA *cd = GetConfigData();

	// Open the service control manager
	g_hSCM = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
	if (!g_hSCM) Die("Unable to open the service control manager");

	// Stop the old driver service if its running
	g_hDriverService = OpenService(g_hSCM, PROCFILTER_DRIVER_SERVICE_NAME, SERVICE_START | SERVICE_STOP | DELETE | SERVICE_QUERY_STATUS);
	if (g_hDriverService) {
		if (!ServiceStop(g_hDriverService, 2 * 60 * 1000)) Die("Unable to stop previously running driver service");
		LogDebugFmt("Opened driver service");
	} else {
		Die("Unable to open old driver service: %u", GetLastError());
	}

	// Service handle opened and the driver is to be started
	// Start the driver service
	BOOL rc = StartService(g_hDriverService, 0, NULL);
	DWORD dwErrorCode = GetLastError();
	if (!rc) Die("Unable to start driver service: %u", dwErrorCode);

	// It's running, so open it
	g_hDriver = CreateFileW(PROCFILTER_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
	if (g_hDriver == INVALID_HANDLE_VALUE) {
		DWORD dwErrorCode = GetLastError();
		LogCriticalFmt("Error opening driver: 0x%08X", dwErrorCode);
		Die("Error opening driver service %ls: %ls", cd->szProcFilterDriver, ErrorText(dwErrorCode));
	}

	// Send the driver its configuration
	PROCFILTER_CONFIGURATION yc;
	ZeroMemory(&yc, sizeof(PROCFILTER_CONFIGURATION));
	yc.dwProcFilterRequestSize = sizeof(PROCFILTER_REQUEST);
	yc.dwProcMaxFilterRequestSize = PROCFILTER_REQUEST_SIZE;
	yc.bDenyProcessCreationOnFailedScan = cd->bDenyProcessCreationOnFailedScan;

	// Always force thread/image events on in debug builds
#if defined(_DEBUG)
	yc.bWantThreadEvents = true;
	yc.bWantImageLoadEvents = true;
#else
	yc.bWantThreadEvents = ApiWantThreadEvents();
	yc.bWantImageLoadEvents = cd->bScanFileOnImageLoad || cd->bScanMemoryOnImageLoad || ApiWantImageLoadEvents();
#endif

	// Create the event to be signalled when device configuration succeeds
	HANDLE hControlDeviceEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (!hControlDeviceEvent) Die("Unable to create event for DeviceIoControl()");
	OVERLAPPED overlapped;
	ZeroMemory(&overlapped, sizeof(OVERLAPPED));
	overlapped.hEvent = hControlDeviceEvent;
	rc = DeviceIoControl(g_hDriver, IOCTL_PROCFILTER_CONFIGURE, &yc, sizeof(PROCFILTER_CONFIGURATION), NULL, 0, NULL, &overlapped);
	if (!rc && GetLastError() == ERROR_IO_PENDING) {
		DWORD dwBytesRead = 0;
		if (!GetOverlappedResult(g_hDriver, &overlapped, &dwBytesRead, TRUE)) {
			Die("GetOverlappedResult() failure for DeviceIoControl(): %d", GetLastError());
		}
	} else if (!rc) {
		Die("DeviceIoControl() failure: %d", GetLastError());
	}

	CloseHandle(hControlDeviceEvent);

	LogWarning("Started driver");
}
// Getter for the logging configuration data
HRESULT CFrameProcessor_J1939::FPJ1_GetConfigData(xmlNodePtr pNodePtr)
{
    return GetConfigData(pNodePtr);
}
// Getter for the logging configuration data
HRESULT CFrameProcessor_J1939::FPJ1_GetConfigData(BYTE** ppvConfigData, UINT& unLength)
{
    return GetConfigData(ppvConfigData, unLength);
}
Example #13
0
//
// Perform the scanning as specified in the various input parameters
//
void
Scan(DWORD dwEventType, int dScanContext, PROCFILTER_EVENT *e, YARASCAN_CONTEXT *ctx, HANDLE hDriver, HANDLE hWriteCompletionEvent, DWORD dwProcessId, DWORD dwParentProcessId, WCHAR *lpszFileName, void *lpImageBase, void *lpvScanDataArray)
{
	if (!lpszFileName) return;

	LONG64 llStart = GetPerformanceCount();

	CONFIG_DATA *cd = GetConfigData();

	bool bScanFile = false;
	bool bScanMemory = false;
	
	bool bBlock = false;
	bool bLog = false;
	bool bQuarantine = false;

	// Pull the scan parameters out of config
	if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) {
		bScanFile = cd->bScanFileOnProcessCreate;
		bScanMemory = cd->bScanMemoryOnProcessCreate;
	} else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_TERMINATE) {
		bScanFile = cd->bScanFileOnProcessTerminate;
		bScanMemory = cd->bScanMemoryOnProcessTerminate;
	} else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PERIODIC_SCAN) {
		bScanFile = cd->bScanFileOnPeriodic;
		bScanMemory = cd->bScanMemoryOnPeriodic;
	} else if (dScanContext == PROCFILTER_SCAN_CONTEXT_IMAGE_LOAD) {
		bScanFile = cd->bScanFileOnImageLoad;
		bScanMemory = cd->bScanMemoryOnImageLoad;
	} else {
		Die("Invalid context passed to Scan(): %d", dScanContext);
	}

	// Initialize the API event with the passed-in parameters
	ApiEventReinit(e, PROCFILTER_EVENT_YARA_SCAN_INIT);
	e->dwProcessId = dwProcessId;
	e->dwParentProcessId = dwParentProcessId;
	e->lpszFileName = lpszFileName;
	e->dScanContext = dScanContext;
	e->bScanFile = bScanFile;
	e->bScanMemory = bScanMemory;
	e->lpvScanData = lpvScanDataArray;

	// Export the event to the API and handle the result flags
	DWORD dwPluginResultFlags = ApiEventExport(e);
	if (dwPluginResultFlags & PROCFILTER_RESULT_BLOCK_PROCESS)     bBlock = true;
	if (dwPluginResultFlags & PROCFILTER_RESULT_DONT_SCAN_MEMORY)  bScanMemory = false;
	if (dwPluginResultFlags & PROCFILTER_RESULT_FORCE_SCAN_MEMORY) bScanMemory = true;
	if (dwPluginResultFlags & PROCFILTER_RESULT_DONT_SCAN_FILE)    bScanFile = false;
	if (dwPluginResultFlags & PROCFILTER_RESULT_FORCE_SCAN_FILE)   bScanFile = true;
	if (dwPluginResultFlags & PROCFILTER_RESULT_QUARANTINE)        bQuarantine = true;
	
	// Scan the file if requested
	SCAN_RESULT srFileResult;
	ZeroMemory(&srFileResult, sizeof(SCAN_RESULT));
	if (bScanFile) {
		CALLBACK_USER_DATA cud = { e, dwProcessId, lpszFileName, lpvScanDataArray, dScanContext, PROCFILTER_MATCH_FILE };
		YarascanScanFile(ctx, lpszFileName, cd->dwScanFileSizeLimit, OnMatchCallback, OnMetaCallback, &cud, &srFileResult);
		if (srFileResult.bScanSuccessful) {
			bBlock |= srFileResult.bBlock;
			bLog |= srFileResult.bLog;
			bQuarantine |= srFileResult.bQuarantine;
		} else {
			EventWriteSCAN_FILE_FAILED(dwProcessId, lpszFileName, srFileResult.szError);
		}
	}
	
	// Scan the memory if requested
	SCAN_RESULT srMemoryResult;
	ZeroMemory(&srMemoryResult, sizeof(SCAN_RESULT));
	if (bScanMemory) {
		CALLBACK_USER_DATA cud = { e, dwProcessId, lpszFileName, lpvScanDataArray, dScanContext, PROCFILTER_MATCH_MEMORY };
		YarascanScanMemory(ctx, dwProcessId, OnMatchCallback, OnMetaCallback, &cud, &srMemoryResult);
		if (srMemoryResult.bScanSuccessful) {
			bBlock |= srMemoryResult.bBlock;
			bLog |= srMemoryResult.bLog;
			bQuarantine |= srMemoryResult.bQuarantine;
		} else {
			EventWriteSCAN_PROCESS_FAILED(dwProcessId, lpszFileName, srMemoryResult.szError);
		}
	}

	// Export the scan results to plugins
	ApiEventReinit(e, PROCFILTER_EVENT_YARA_SCAN_COMPLETE);
	e->dwProcessId = dwProcessId;
	e->dwParentProcessId = dwParentProcessId;
	e->lpszFileName = lpszFileName;
	e->dScanContext = dScanContext;
	e->srFileResult = bScanFile ? &srFileResult : NULL;
	e->srMemoryResult = bScanMemory ? &srMemoryResult : NULL;
	e->bBlockProcess = bBlock;
	e->lpvScanData = lpvScanDataArray;
	dwPluginResultFlags = ApiEventExport(e);
	if (dwPluginResultFlags & PROCFILTER_RESULT_BLOCK_PROCESS)     bBlock = true;
	if (dwPluginResultFlags & PROCFILTER_RESULT_QUARANTINE)        bQuarantine = true;
	
	WCHAR *szFileQuarantineRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szQuarantineRuleNames : NULL;
	WCHAR *szMemoryQuarantineRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szQuarantineRuleNames : NULL;

	// Quarantine here
	if (bQuarantine) {
		char hexdigest[SHA1_HEXDIGEST_LENGTH+1] = { '\0' };
		if (QuarantineFile(lpszFileName, cd->szQuarantineDirectory, cd->dwQuarantineFileSizeLimit, szFileQuarantineRuleNames, szMemoryQuarantineRuleNames, hexdigest)) {
			EventWriteFILE_QUARANTINED(dwProcessId, lpszFileName, hexdigest,
				(bScanFile && srFileResult.bScanSuccessful) ? srFileResult.szQuarantineRuleNames : NULL,
				(bScanMemory && srMemoryResult.bScanSuccessful) ? srMemoryResult.szQuarantineRuleNames : NULL);
		}
	}
	
	// Write the result back to the kernel driver, which releases the process
	bool bProcessBlocked = false;
	if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE || dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_TERMINATE) {
		PROCFILTER_RESPONSE response;
		ZeroMemory(&response, sizeof(PROCFILTER_RESPONSE));
		response.dwEventType = dwEventType;
		response.dwProcessId = dwProcessId;

		// Block the process according to configuration
		if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) {
			if (cd->bDenyProcessCreationOnFailedScan) {
				if (bScanFile && !srFileResult.bScanSuccessful) bBlock = true;
				if (bScanMemory && !srMemoryResult.bScanSuccessful) bBlock = true;
			}
			
			if (bBlock) {
				response.bBlock = true;
			}
		}

		if (DriverSendResponse(hDriver, hWriteCompletionEvent, &response)) {
			if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) bProcessBlocked = true;
		}
	} else if (dScanContext == PROCFILTER_SCAN_CONTEXT_IMAGE_LOAD) {
		PROCFILTER_RESPONSE response;
		ZeroMemory(&response, sizeof(PROCFILTER_RESPONSE));
		response.dwEventType = dwEventType;
		response.dwProcessId = dwProcessId;
		response.lpImageBase = lpImageBase;
		DriverSendResponse(hDriver, hWriteCompletionEvent, &response);
	}

	// Log to event log based on what was sent to the kernel (excluding the quarantining)
	WCHAR *szFileLogRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szLogRuleNames : NULL;
	WCHAR *szFileBlockRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szBlockRuleNames : NULL;
	WCHAR *szFileMatchRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szMatchedRuleNames : NULL;
	WCHAR *szMemoryLogRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szLogRuleNames : NULL;
	WCHAR *szMemoryBlockRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szBlockRuleNames : NULL;
	WCHAR *szMemoryMatchRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szMatchedRuleNames : NULL;
	
	// Log the actions taken according to which events happened
	if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) {
		if (bLog) EventWriteEXECUTION_LOGGED(dwProcessId, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames);
		if (bBlock) EventWriteEXECUTION_BLOCKED(dwProcessId, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames);
	} else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_TERMINATE) {
		if (bLog) EventWriteEXITING_PROCESS_SCAN_MATCHED_LOGGED_RULE(dwProcessId, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames);
		if (bBlock) EventWriteEXITING_PROCESS_SCAN_MATCHED_BLOCKED_RULE(dwProcessId, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames);
	} else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PERIODIC_SCAN) {
		if (bLog) EventWriteRUNNING_PROCESS_MATCHED_LOGGED_RULE(dwProcessId, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames);	
		if (bBlock) {
			EventWriteRUNNING_PROCESS_MATCHED_BLOCKED_RULE(dwProcessId, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames);
			if (TerminateProcessByPid(dwProcessId, true, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames)) {
				bProcessBlocked = true;
			}
		}
	} else if (dScanContext == PROCFILTER_SCAN_CONTEXT_IMAGE_LOAD) {
		if (bLog || bBlock) {
			WCHAR *lpszImageLoaderProcessName = NULL;
			DWORD dwImageLoaderProcessNameSize = sizeof(WCHAR) * (MAX_PATH+1);
			
			HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
			if (hProcess) {
				lpszImageLoaderProcessName = (WCHAR*)_malloca(dwImageLoaderProcessNameSize);
				if (!QueryFullProcessImageNameW(hProcess, PROCESS_NAME_NATIVE, lpszImageLoaderProcessName, &dwImageLoaderProcessNameSize)) {
					_freea(lpszImageLoaderProcessName);
					lpszImageLoaderProcessName = NULL;
				}
				CloseHandle(hProcess);
			}

			if (bLog) EventWriteLOADED_IMAGE_LOGGED(dwProcessId, lpszImageLoaderProcessName, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames);	
			if (bBlock) {
				EventWriteLOADED_IMAGE_BLOCKED(dwProcessId, lpszImageLoaderProcessName, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames);
				if (TerminateProcessByPid(dwProcessId, true, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames)) {
					bProcessBlocked = true;
				}
			}

			if (lpszImageLoaderProcessName) _freea(lpszImageLoaderProcessName);
		}
	}
	
	// Export post-scan notice to plugins
	ApiEventReinit(e, PROCFILTER_EVENT_YARA_SCAN_CLEANUP);
	e->dwProcessId = dwProcessId;
	e->dwParentProcessId = dwParentProcessId;
	e->lpszFileName = lpszFileName;
	e->dScanContext = dScanContext;
	e->srFileResult = bScanFile ? &srFileResult : NULL;
	e->srMemoryResult = bScanMemory ? &srMemoryResult : NULL;
	e->bBlockProcess = bBlock;
	e->bProcessBlocked = bProcessBlocked;
	e->lpvScanData = lpvScanDataArray;
	ApiEventExport(e);

	// Performance data update
	LONG64 llDuration = GetPerformanceCount() - llStart;
	MmaUpdate(&g_Stats[dScanContext].mma, llDuration);
	MmaUpdate(&g_Stats[PROCFILTER_NUM_CONTEXTS].mma, llDuration);
}
/**
 Helper function to refresh the UI widget values
 */
void ConfigMultiRotorWidget::refreshAirframeWidgetsValues(SystemSettings::AirframeTypeOptions frameType)
{
    int channel;
    double value;

    GUIConfigDataUnion config = GetConfigData();
    multiGUISettingsStruct multi = config.multi;

    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    Q_ASSERT(mixerSettings);


    if (frameType == SystemSettings::AIRFRAMETYPE_QUADP)
    {
        // Motors 1/2/3/4 are: N / E / S / W
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorN);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorS);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorW);

        // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
        // This assumes that all vectors are identical - if not, the user should use the
        // "custom" setting.

        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
            m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
            setYawMixLevel( -qRound(value/1.27) );

            channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
            m_aircraft->mrRollMixLevel->setValue( -qRound(value/1.27));

        }
    }
    else if (frameType == SystemSettings::AIRFRAMETYPE_QUADX)
    {
        // Motors 1/2/3/4 are: NW / NE / SE / SW
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorNW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorNE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorSE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorSW);

        // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
        // This assumes that all vectors are identical - if not, the user should use the
        // "custom" setting.
        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
            m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
            setYawMixLevel( -qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
            m_aircraft->mrRollMixLevel->setValue( qRound(value/1.27));

        }

    }
    else if (frameType == SystemSettings::AIRFRAMETYPE_HEXA)
    {
        // Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW

        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorN);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorNE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorSE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorS);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox5,multi.VTOLMotorSW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox6,multi.VTOLMotorNW);

        // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
        // This assumes that all vectors are identical - if not, the user should use the
        // "custom" setting.

        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
            m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
            setYawMixLevel( -qRound(value/1.27) );

            //change channels
            channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
            m_aircraft->mrRollMixLevel->setValue( -qRound(value/1.27) );

        }


    }
    else if (frameType == SystemSettings::AIRFRAMETYPE_HEXAX)
    {
        // Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW

        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorNE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorSE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorSW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox5,multi.VTOLMotorW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox6,multi.VTOLMotorNW);

        // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
        // This assumes that all vectors are identical - if not, the user should use the
        // "custom" setting.

        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
            m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
            setYawMixLevel( -qRound(value/1.27) );

            channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
            m_aircraft->mrRollMixLevel->setValue( -qRound(value/1.27) );
        }
    }
    else if (frameType == SystemSettings::AIRFRAMETYPE_HEXACOAX)
    {
        // Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE

        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorNW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorNE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox5,multi.VTOLMotorS);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox6,multi.VTOLMotorSE);

        // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
        // This assumes that all vectors are identical - if not, the user should use the
        // "custom" setting.
        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
            m_aircraft->mrPitchMixLevel->setValue( qRound(2*value/1.27) );

            channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
            setYawMixLevel( qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
            m_aircraft->mrRollMixLevel->setValue( qRound(value/1.27) );
        }
    }
    else if (frameType ==  SystemSettings::AIRFRAMETYPE_OCTO ||
             frameType == SystemSettings::AIRFRAMETYPE_OCTOV ||
             frameType == SystemSettings::AIRFRAMETYPE_OCTOCOAXP)
    {
        // Motors 1 to 8 are N / NE / E / etc

        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorN);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorNE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorSE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox5,multi.VTOLMotorS);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox6,multi.VTOLMotorSW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox7,multi.VTOLMotorW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox8,multi.VTOLMotorNW);

        // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
        // This assumes that all vectors are identical - if not, the user should use the
        // "custom" setting.
        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            if (frameType == SystemSettings::AIRFRAMETYPE_OCTO) {
                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
                m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
                setYawMixLevel( -qRound(value/1.27) );

                //change channels
                channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
                m_aircraft->mrRollMixLevel->setValue( -qRound(value/1.27) );
            }
            else if (frameType == SystemSettings::AIRFRAMETYPE_OCTOV) {
                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
                m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
                setYawMixLevel( -qRound(value/1.27) );

                //change channels
                channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
                m_aircraft->mrRollMixLevel->setValue( -qRound(value/1.27) );
            }
            else if (frameType == SystemSettings::AIRFRAMETYPE_OCTOCOAXP) {
                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
                m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
                setYawMixLevel( -qRound(value/1.27) );

                //change channels
                channel = m_aircraft->multiMotorChannelBox3->currentIndex() - 1;
                value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
                m_aircraft->mrRollMixLevel->setValue( -qRound(value/1.27) );
            }

        }
    }
    else if (frameType == SystemSettings::AIRFRAMETYPE_OCTOCOAXX)
    {
        // Motors 1 to 8 are N / NE / E / etc

        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorNW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorN);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorNE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox5,multi.VTOLMotorSE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox6,multi.VTOLMotorS);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox7,multi.VTOLMotorSW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox8,multi.VTOLMotorW);

        // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
        // This assumes that all vectors are identical - if not, the user should use the
        // "custom" setting.
        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
            m_aircraft->mrPitchMixLevel->setValue( qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW);
            setYawMixLevel( -qRound(value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
            m_aircraft->mrRollMixLevel->setValue( qRound(value/1.27) );
        }
    }
    else if (frameType == SystemSettings::AIRFRAMETYPE_TRI)
    {
        // Motors 1 to 8 are N / NE / E / etc

        setComboCurrentIndex(m_aircraft->multiMotorChannelBox1,multi.VTOLMotorNW);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox2,multi.VTOLMotorNE);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox3,multi.VTOLMotorS);
        setComboCurrentIndex(m_aircraft->multiMotorChannelBox4,multi.VTOLMotorS);
        setComboCurrentIndex(m_aircraft->triYawChannelBox,multi.TRIYaw);

        channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
        if (channel > -1)
        {
            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_PITCH);
            m_aircraft->mrPitchMixLevel->setValue( qRound(2*value/1.27) );

            value = getMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_ROLL);
            m_aircraft->mrRollMixLevel->setValue( qRound(value/1.27) );

        }
    }

    drawAirframe(frameType);
}
/**
 Helper function to update the UI widget objects
 */
SystemSettings::AirframeTypeOptions ConfigMultiRotorWidget::updateConfigObjectsFromWidgets()
{
    SystemSettings::AirframeTypeOptions airframeType = SystemSettings::AIRFRAMETYPE_FIXEDWING;
    QList<QString> motorList;

    MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager());
    Q_ASSERT(mixerSettings);

    // Curve is also common to all quads:
    setThrottleCurve(mixerSettings, MixerSettings::MIXER1VECTOR_THROTTLECURVE1, m_aircraft->multiThrottleCurve->getCurve() );

    if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_QUADP) {
        airframeType = SystemSettings::AIRFRAMETYPE_QUADP;
        setupQuad(true);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_QUADX) {
        airframeType = SystemSettings::AIRFRAMETYPE_QUADX;
        setupQuad(false);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_HEXA) {
        airframeType = SystemSettings::AIRFRAMETYPE_HEXA;
        setupHexa(true);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_HEXAX) {
        airframeType = SystemSettings::AIRFRAMETYPE_HEXAX;
        setupHexa(false);
    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_HEXACOAX) {
        airframeType = SystemSettings::AIRFRAMETYPE_HEXACOAX;

        //Show any config errors in GUI
        if (throwConfigError(6)) {
            return airframeType;
        }
        motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE"
                  << "VTOLMotorS" << "VTOLMotorSE";
        setupMotors(motorList);

        // Motor 1 to 6, Y6 Layout:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  0.5,  1, -1},
            {  0.5,  1,  1},
            {  0.5, -1, -1},
            {  0.5, -1,  1},
            { -1,    0, -1},
            { -1,    0,  1},
            {  0,    0,  0},
            {  0,    0,  0}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTO) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTO;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;

        }
        motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
                  << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
        setupMotors(motorList);
        // Motor 1 to 8:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  1,  0, -1},
            {  1, -1,  1},
            {  0, -1, -1},
            { -1, -1,  1},
            { -1,  0, -1},
            { -1,  1,  1},
            {  0,  1, -1},
            {  1,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTOV) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTOV;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;
        }
        motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
                  << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
        setupMotors(motorList);
        // Motor 1 to 8:
        // IMPORTANT: Assumes evenly spaced engines
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  0.33, -1, -1},
            {  1   , -1,  1},
            { -1   , -1, -1},
            { -0.33, -1,  1},
            { -0.33,  1, -1},
            { -1   ,  1,  1},
            {  1   ,  1, -1},
            {  0.33,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTOCOAXP) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTOCOAXP;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;
        }
        motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
                  << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
        setupMotors(motorList);
        // Motor 1 to 8:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  1,  0, -1},
            {  1,  0,  1},
            {  0, -1, -1},
            {  0, -1,  1},
            { -1,  0, -1},
            { -1,  0,  1},
            {  0,  1, -1},
            {  0,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_OCTOCOAXX) {
        airframeType = SystemSettings::AIRFRAMETYPE_OCTOCOAXX;

        //Show any config errors in GUI
        if (throwConfigError(8)) {
            return airframeType;
        }
        motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE"
                  << "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW";
        setupMotors(motorList);
        // Motor 1 to 8:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  1,  1, -1},
            {  1,  1,  1},
            {  1, -1, -1},
            {  1, -1,  1},
            { -1, -1, -1},
            { -1, -1,  1},
            { -1,  1, -1},
            { -1,  1,  1}
        };
        setupMultiRotorMixer(mixer);
        m_aircraft->mrStatusLabel->setText("Configuration OK");

    } else if (m_aircraft->multirotorFrameType->itemData(m_aircraft->multirotorFrameType->currentIndex()) == SystemSettings::AIRFRAMETYPE_TRI) {
        airframeType = SystemSettings::AIRFRAMETYPE_TRI;

        //Show any config errors in GUI
        if (throwConfigError(3)) {
            return airframeType;

        }
        if (m_aircraft->triYawChannelBox->currentText() == "None") {
            m_aircraft->mrStatusLabel->setText("<font color='red'>Error: Assign a Yaw channel</font>");
            return airframeType;
        }
        motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
        setupMotors(motorList);

        GUIConfigDataUnion config = GetConfigData();
        config.multi.TRIYaw = m_aircraft->triYawChannelBox->currentIndex();
        SetConfigData(config);


        // Motor 1 to 6, Y6 Layout:
        //     pitch   roll    yaw
        double mixer [8][3] = {
            {  0.5,  1,  0},
            {  0.5, -1,  0},
            { -1,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0},
            {  0,  0,  0}
        };
        setupMultiRotorMixer(mixer);

        //tell the mixer about tricopter yaw channel

        int channel = m_aircraft->triYawChannelBox->currentIndex()-1;
        if (channel > -1) {
            setMixerType(mixerSettings, channel, MixerSettings::MIXER1TYPE_SERVO);
            setMixerVectorValue(mixerSettings, channel, MixerSettings::MIXER1VECTOR_YAW, 127);
        }

        m_aircraft->mrStatusLabel->setText(tr("Configuration OK"));

    }

    return airframeType;
}
// Getter for the logging configuration data
HRESULT CFrameProcessor_LIN::FPL_GetConfigData(xmlNodePtr pxmlNodePtr)
{
    return GetConfigData(pxmlNodePtr);
}