mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-11-29 07:24:13 +01:00
Merge branch 'next' into revo
Conflicts: flight/PiOS/Boards/STM32F4xx_Revolution.h flight/Revolution/System/inc/pios_config.h package/Makefile
This commit is contained in:
commit
f5b2575c88
@ -1,43 +1,43 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file pios_config.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief PiOS configuration header.
|
||||
* - Central compile time config for the project.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_CONFIG_H
|
||||
#define PIOS_CONFIG_H
|
||||
|
||||
/* Enable/Disable PiOS Modules */
|
||||
#define PIOS_INCLUDE_DELAY
|
||||
#define PIOS_INCLUDE_IRQ
|
||||
#define PIOS_INCLUDE_LED
|
||||
#define PIOS_INCLUDE_SPI
|
||||
#define PIOS_INCLUDE_SYS
|
||||
#define PIOS_INCLUDE_IAP
|
||||
#define PIOS_INCLUDE_USB
|
||||
#define PIOS_INCLUDE_USB_HID
|
||||
#define PIOS_INCLUDE_COM_MSG
|
||||
#define PIOS_INCLUDE_BL_HELPER
|
||||
#define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT
|
||||
|
||||
#endif /* PIOS_CONFIG_H */
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file pios_config.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief PiOS configuration header.
|
||||
* - Central compile time config for the project.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_CONFIG_H
|
||||
#define PIOS_CONFIG_H
|
||||
|
||||
/* Enable/Disable PiOS Modules */
|
||||
#define PIOS_INCLUDE_DELAY
|
||||
#define PIOS_INCLUDE_IRQ
|
||||
#define PIOS_INCLUDE_LED
|
||||
#define PIOS_INCLUDE_SPI
|
||||
#define PIOS_INCLUDE_SYS
|
||||
#define PIOS_INCLUDE_IAP
|
||||
#define PIOS_INCLUDE_USB
|
||||
#define PIOS_INCLUDE_USB_HID
|
||||
#define PIOS_INCLUDE_COM_MSG
|
||||
#define PIOS_INCLUDE_BL_HELPER
|
||||
#define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT
|
||||
|
||||
#endif /* PIOS_CONFIG_H */
|
||||
|
@ -1,46 +1,46 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup OpenPilotModules OpenPilot Modules
|
||||
* @{
|
||||
* @addtogroup TelemetryModule Telemetry Module
|
||||
* @brief Main telemetry module
|
||||
* Starts three tasks (RX, TX, and priority TX) that watch event queues
|
||||
* and handle all the telemetry of the UAVobjects
|
||||
* @{
|
||||
*
|
||||
* @file telemetry.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief Include file of the telemetry module.
|
||||
* As with all modules only the initialize function is exposed all other
|
||||
* interactions with the module take place through the event queue and
|
||||
* objects.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TELEMETRY_H
|
||||
#define TELEMETRY_H
|
||||
|
||||
int32_t TelemetryInitialize(void);
|
||||
|
||||
#endif // TELEMETRY_H
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup OpenPilotModules OpenPilot Modules
|
||||
* @{
|
||||
* @addtogroup TelemetryModule Telemetry Module
|
||||
* @brief Main telemetry module
|
||||
* Starts three tasks (RX, TX, and priority TX) that watch event queues
|
||||
* and handle all the telemetry of the UAVobjects
|
||||
* @{
|
||||
*
|
||||
* @file telemetry.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief Include file of the telemetry module.
|
||||
* As with all modules only the initialize function is exposed all other
|
||||
* interactions with the module take place through the event queue and
|
||||
* objects.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TELEMETRY_H
|
||||
#define TELEMETRY_H
|
||||
|
||||
int32_t TelemetryInitialize(void);
|
||||
|
||||
#endif // TELEMETRY_H
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
@ -1,37 +1,37 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup OpenPilotModules OpenPilot Modules
|
||||
* @{
|
||||
* @addtogroup Sensors Sensors Module
|
||||
* @{
|
||||
*
|
||||
* @file attitude.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
|
||||
* @brief Acquires sensor data and fuses it into attitude estimate for CC
|
||||
*
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef SENSORS_H
|
||||
#define SENSORS_H
|
||||
|
||||
#include "openpilot.h"
|
||||
|
||||
int32_t SensorsInitialize(void);
|
||||
|
||||
#endif // SENSORS_H
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup OpenPilotModules OpenPilot Modules
|
||||
* @{
|
||||
* @addtogroup Sensors Sensors Module
|
||||
* @{
|
||||
*
|
||||
* @file attitude.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
|
||||
* @brief Acquires sensor data and fuses it into attitude estimate for CC
|
||||
*
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef SENSORS_H
|
||||
#define SENSORS_H
|
||||
|
||||
#include "openpilot.h"
|
||||
|
||||
int32_t SensorsInitialize(void);
|
||||
|
||||
#endif // SENSORS_H
|
||||
|
@ -1,2323 +1,2323 @@
|
||||
/*
|
||||
FreeRTOS V6.0.4 - Copyright (C) 2010 Real Time Engineers Ltd.
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* If you are: *
|
||||
* *
|
||||
* + New to FreeRTOS, *
|
||||
* + Wanting to learn FreeRTOS or multitasking in general quickly *
|
||||
* + Looking for basic training, *
|
||||
* + Wanting to improve your FreeRTOS skills and productivity *
|
||||
* *
|
||||
* then take a look at the FreeRTOS eBook *
|
||||
* *
|
||||
* "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
* A pdf reference manual is also available. Both are usually delivered *
|
||||
* to your inbox within 20 minutes to two hours when purchased between 8am *
|
||||
* and 8pm GMT (although please allow up to 24 hours in case of *
|
||||
* exceptional circumstances). Thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
***NOTE*** The exception to the GPL is included to allow you to distribute
|
||||
a combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details. You should have received a copy of the GNU General Public
|
||||
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "StackMacros.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
/*
|
||||
* Macro to define the amount of stack available to the idle task.
|
||||
*/
|
||||
#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/*
|
||||
* Task control block. A task control block (TCB) is allocated to each task,
|
||||
* and stores the context of the task.
|
||||
*/
|
||||
typedef struct tskTaskControlBlock
|
||||
{
|
||||
volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
|
||||
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
|
||||
#endif
|
||||
|
||||
xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
|
||||
xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
|
||||
unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
|
||||
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
|
||||
signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
|
||||
|
||||
#if ( portSTACK_GROWTH > 0 )
|
||||
portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
|
||||
#endif
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
unsigned portBASE_TYPE uxCriticalNesting;
|
||||
#endif
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
|
||||
#endif
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
|
||||
#endif
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
pdTASK_HOOK_CODE pxTaskTag;
|
||||
#endif
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
|
||||
#endif
|
||||
|
||||
} tskTCB;
|
||||
|
||||
|
||||
/*
|
||||
* Some kernel aware debuggers require data to be viewed to be global, rather
|
||||
* than file scope.
|
||||
*/
|
||||
#ifdef portREMOVE_STATIC_QUALIFIER
|
||||
#define static
|
||||
#endif
|
||||
|
||||
/*lint -e956 */
|
||||
PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
|
||||
|
||||
/* Lists for ready and blocked tasks. --------------------*/
|
||||
|
||||
PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
|
||||
PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
|
||||
PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
|
||||
PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
|
||||
PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
|
||||
PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
|
||||
PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
|
||||
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
|
||||
|
||||
#endif
|
||||
|
||||
/* File private variables. --------------------------------*/
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
|
||||
PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0;
|
||||
PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
|
||||
PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
|
||||
PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
|
||||
PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
|
||||
PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
||||
PRIVILEGED_DATA static char pcStatsString[ 50 ] ;
|
||||
PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
|
||||
static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
/* Debugging and trace facilities private variables and macros. ------------*/
|
||||
|
||||
/*
|
||||
* The value used to fill the stack of a task when the task is created. This
|
||||
* is used purely for checking the high water mark for tasks.
|
||||
*/
|
||||
#define tskSTACK_FILL_BYTE ( 0xa5 )
|
||||
|
||||
/*
|
||||
* Macros used by vListTask to indicate which state a task is in.
|
||||
*/
|
||||
#define tskBLOCKED_CHAR ( ( signed char ) 'B' )
|
||||
#define tskREADY_CHAR ( ( signed char ) 'R' )
|
||||
#define tskDELETED_CHAR ( ( signed char ) 'D' )
|
||||
#define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
|
||||
|
||||
/*
|
||||
* Macros and private variables used by the trace facility.
|
||||
*/
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
#define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )
|
||||
PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;
|
||||
PRIVILEGED_DATA static signed char *pcTraceBufferStart;
|
||||
PRIVILEGED_DATA static signed char *pcTraceBufferEnd;
|
||||
PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
|
||||
static unsigned portBASE_TYPE uxPreviousTask = 255;
|
||||
PRIVILEGED_DATA static char pcStatusString[ 50 ];
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Macro that writes a trace of scheduler activity to a buffer. This trace
|
||||
* shows which task is running when and is very useful as a debugging tool.
|
||||
* As this macro is called each context switch it is a good idea to undefine
|
||||
* it if not using the facility.
|
||||
*/
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
#define vWriteTraceToBuffer() \
|
||||
{ \
|
||||
if( xTracing ) \
|
||||
{ \
|
||||
if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
|
||||
{ \
|
||||
if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
|
||||
{ \
|
||||
uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
|
||||
*( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \
|
||||
pcTraceBuffer += sizeof( unsigned long ); \
|
||||
*( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \
|
||||
pcTraceBuffer += sizeof( unsigned long ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
xTracing = pdFALSE; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define vWriteTraceToBuffer()
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Place the task represented by pxTCB into the appropriate ready queue for
|
||||
* the task. It is inserted at the end of the list. One quirk of this is
|
||||
* that if the task being inserted is at the same priority as the currently
|
||||
* executing task, then it will only be rescheduled after the currently
|
||||
* executing task has been rescheduled.
|
||||
*/
|
||||
#define prvAddTaskToReadyQueue( pxTCB ) \
|
||||
{ \
|
||||
if( pxTCB->uxPriority > uxTopReadyPriority ) \
|
||||
{ \
|
||||
uxTopReadyPriority = pxTCB->uxPriority; \
|
||||
} \
|
||||
vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Macro that looks at the list of tasks that are currently delayed to see if
|
||||
* any require waking.
|
||||
*
|
||||
* Tasks are stored in the queue in the order of their wake time - meaning
|
||||
* once one tasks has been found whose timer has not expired we need not look
|
||||
* any further down the list.
|
||||
*/
|
||||
#define prvCheckDelayedTasks() \
|
||||
{ \
|
||||
register tskTCB *pxTCB; \
|
||||
\
|
||||
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
|
||||
{ \
|
||||
if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
|
||||
{ \
|
||||
break; \
|
||||
} \
|
||||
vListRemove( &( pxTCB->xGenericListItem ) ); \
|
||||
/* Is the task waiting on an event also? */ \
|
||||
if( pxTCB->xEventListItem.pvContainer ) \
|
||||
{ \
|
||||
vListRemove( &( pxTCB->xEventListItem ) ); \
|
||||
} \
|
||||
prvAddTaskToReadyQueue( pxTCB ); \
|
||||
} \
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Several functions take an xTaskHandle parameter that can optionally be NULL,
|
||||
* where NULL is used to indicate that the handle of the currently executing
|
||||
* task should be used in place of the parameter. This macro simply checks to
|
||||
* see if the parameter is NULL and returns a pointer to the appropriate TCB.
|
||||
*/
|
||||
#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
|
||||
|
||||
|
||||
/* File private functions. --------------------------------*/
|
||||
|
||||
/*
|
||||
* Utility to ready a TCB for a given task. Mainly just copies the parameters
|
||||
* into the TCB structure.
|
||||
*/
|
||||
static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Utility to ready all the lists used by the scheduler. This is called
|
||||
* automatically upon the creation of the first task.
|
||||
*/
|
||||
static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* The idle task, which as all tasks is implemented as a never ending loop.
|
||||
* The idle task is automatically created and added to the ready lists upon
|
||||
* creation of the first user task.
|
||||
*
|
||||
* The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
|
||||
* language extensions. The equivalent prototype for this function is:
|
||||
*
|
||||
* void prvIdleTask( void *pvParameters );
|
||||
*
|
||||
*/
|
||||
static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
|
||||
|
||||
/*
|
||||
* Utility to free all memory allocated by the scheduler to hold a TCB,
|
||||
* including the stack pointed to by the TCB.
|
||||
*
|
||||
* This does not free memory allocated by the task itself (i.e. memory
|
||||
* allocated by calls to pvPortMalloc from within the tasks application code).
|
||||
*/
|
||||
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
|
||||
|
||||
static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used only by the idle task. This checks to see if anything has been placed
|
||||
* in the list of tasks waiting to be deleted. If so the task is cleaned up
|
||||
* and its TCB deleted.
|
||||
*/
|
||||
static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Allocates memory from the heap for a TCB and associated stack. Checks the
|
||||
* allocation was successful.
|
||||
*/
|
||||
static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Called from vTaskList. vListTasks details all the tasks currently under
|
||||
* control of the scheduler. The tasks may be in one of a number of lists.
|
||||
* prvListTaskWithinSingleList accepts a list and details the tasks from
|
||||
* within just that list.
|
||||
*
|
||||
* THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
|
||||
* NORMAL APPLICATION CODE.
|
||||
*/
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When a task is created, the stack of the task is filled with a known value.
|
||||
* This function determines the 'high water mark' of the task stack by
|
||||
* determining how much of the stack remains at the original preset value.
|
||||
*/
|
||||
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
||||
|
||||
static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*lint +e956 */
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* TASK CREATION API documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
|
||||
{
|
||||
signed portBASE_TYPE xReturn;
|
||||
tskTCB * pxNewTCB;
|
||||
|
||||
/* Allocate the memory required by the TCB and stack for the new task,
|
||||
checking that the allocation was successful. */
|
||||
pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
|
||||
|
||||
if( pxNewTCB != NULL )
|
||||
{
|
||||
portSTACK_TYPE *pxTopOfStack;
|
||||
|
||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||
/* Should the task be created in privileged mode? */
|
||||
portBASE_TYPE xRunPrivileged;
|
||||
if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
|
||||
{
|
||||
xRunPrivileged = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xRunPrivileged = pdFALSE;
|
||||
}
|
||||
uxPriority &= ~portPRIVILEGE_BIT;
|
||||
#endif /* portUSING_MPU_WRAPPERS == 1 */
|
||||
|
||||
/* Calculate the top of stack address. This depends on whether the
|
||||
stack grows from high memory to low (as per the 80x86) or visa versa.
|
||||
portSTACK_GROWTH is used to make the result positive or negative as
|
||||
required by the port. */
|
||||
#if( portSTACK_GROWTH < 0 )
|
||||
{
|
||||
pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
|
||||
pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK ) );
|
||||
}
|
||||
#else
|
||||
{
|
||||
pxTopOfStack = pxNewTCB->pxStack;
|
||||
|
||||
/* If we want to use stack checking on architectures that use
|
||||
a positive stack growth direction then we also need to store the
|
||||
other extreme of the stack space. */
|
||||
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup the newly allocated TCB with the initial state of the task. */
|
||||
prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
|
||||
|
||||
/* Initialize the TCB stack to look as if the task was already running,
|
||||
but had been interrupted by the scheduler. The return address is set
|
||||
to the start of the task function. Once the stack has been initialised
|
||||
the top of stack variable is updated. */
|
||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||
{
|
||||
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
|
||||
}
|
||||
#else
|
||||
{
|
||||
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We are going to manipulate the task queues to add this task to a
|
||||
ready list, so must make sure no interrupts occur. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxCurrentNumberOfTasks++;
|
||||
if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
|
||||
{
|
||||
/* As this is the first task it must also be the current task. */
|
||||
pxCurrentTCB = pxNewTCB;
|
||||
|
||||
/* This is the first task to be created so do the preliminary
|
||||
initialisation required. We will not recover if this call
|
||||
fails, but we will report the failure. */
|
||||
prvInitialiseTaskLists();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the scheduler is not already running, make this task the
|
||||
current task if it is the highest priority task to be created
|
||||
so far. */
|
||||
if( xSchedulerRunning == pdFALSE )
|
||||
{
|
||||
if( pxCurrentTCB->uxPriority <= uxPriority )
|
||||
{
|
||||
pxCurrentTCB = pxNewTCB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember the top priority to make context switching faster. Use
|
||||
the priority in pxNewTCB as this has been capped to a valid value. */
|
||||
if( pxNewTCB->uxPriority > uxTopUsedPriority )
|
||||
{
|
||||
uxTopUsedPriority = pxNewTCB->uxPriority;
|
||||
}
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
{
|
||||
/* Add a counter into the TCB for tracing only. */
|
||||
pxNewTCB->uxTCBNumber = uxTaskNumber;
|
||||
}
|
||||
#endif
|
||||
uxTaskNumber++;
|
||||
|
||||
prvAddTaskToReadyQueue( pxNewTCB );
|
||||
|
||||
xReturn = pdPASS;
|
||||
traceTASK_CREATE( pxNewTCB );
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
||||
traceTASK_CREATE_FAILED( pxNewTCB );
|
||||
}
|
||||
|
||||
if( xReturn == pdPASS )
|
||||
{
|
||||
if( ( void * ) pxCreatedTask != NULL )
|
||||
{
|
||||
/* Pass the TCB out - in an anonymous way. The calling function/
|
||||
task can use this as a handle to delete the task later if
|
||||
required.*/
|
||||
*pxCreatedTask = ( xTaskHandle ) pxNewTCB;
|
||||
}
|
||||
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
/* If the created task is of a higher priority than the current task
|
||||
then it should run now. */
|
||||
if( pxCurrentTCB->uxPriority < uxPriority )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
|
||||
void vTaskDelete( xTaskHandle pxTaskToDelete )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* Ensure a yield is performed if the current task is being
|
||||
deleted. */
|
||||
if( pxTaskToDelete == pxCurrentTCB )
|
||||
{
|
||||
pxTaskToDelete = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are deleting ourselves. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
|
||||
|
||||
/* Remove task from the ready list and place in the termination list.
|
||||
This will stop the task from be scheduled. The idle task will check
|
||||
the termination list and free up any memory allocated by the
|
||||
scheduler for the TCB and stack. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Is the task waiting on an event also? */
|
||||
if( pxTCB->xEventListItem.pvContainer )
|
||||
{
|
||||
vListRemove( &( pxTCB->xEventListItem ) );
|
||||
}
|
||||
|
||||
vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Increment the ucTasksDeleted variable so the idle task knows
|
||||
there is a task that has been deleted and that it should therefore
|
||||
check the xTasksWaitingTermination list. */
|
||||
++uxTasksDeleted;
|
||||
|
||||
/* Increment the uxTaskNumberVariable also so kernel aware debuggers
|
||||
can detect that the task lists need re-generating. */
|
||||
uxTaskNumber++;
|
||||
|
||||
traceTASK_DELETE( pxTCB );
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Force a reschedule if we have just deleted the current task. */
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
if( ( void * ) pxTaskToDelete == NULL )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* TASK CONTROL API documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskDelayUntil == 1 )
|
||||
|
||||
void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Generate the tick time at which the task wants to wake. */
|
||||
xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
|
||||
|
||||
if( xTickCount < *pxPreviousWakeTime )
|
||||
{
|
||||
/* The tick count has overflowed since this function was
|
||||
lasted called. In this case the only time we should ever
|
||||
actually delay is if the wake time has also overflowed,
|
||||
and the wake time is greater than the tick time. When this
|
||||
is the case it is as if neither time had overflowed. */
|
||||
if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
|
||||
{
|
||||
xShouldDelay = pdTRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The tick time has not overflowed. In this case we will
|
||||
delay if either the wake time has overflowed, and/or the
|
||||
tick time is less than the wake time. */
|
||||
if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
|
||||
{
|
||||
xShouldDelay = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the wake time ready for the next call. */
|
||||
*pxPreviousWakeTime = xTimeToWake;
|
||||
|
||||
if( xShouldDelay )
|
||||
{
|
||||
traceTASK_DELAY_UNTIL();
|
||||
|
||||
/* We must remove ourselves from the ready list before adding
|
||||
ourselves to the blocked list as the same list item is used for
|
||||
both lists. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
|
||||
/* The list item will be inserted in wake time order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the
|
||||
overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the
|
||||
current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
xAlreadyYielded = xTaskResumeAll();
|
||||
|
||||
/* Force a reschedule if xTaskResumeAll has not already done so, we may
|
||||
have put ourselves to sleep. */
|
||||
if( !xAlreadyYielded )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskDelay == 1 )
|
||||
|
||||
void vTaskDelay( portTickType xTicksToDelay )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
|
||||
|
||||
/* A delay time of zero just forces a reschedule. */
|
||||
if( xTicksToDelay > ( portTickType ) 0 )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
traceTASK_DELAY();
|
||||
|
||||
/* A task that is removed from the event list while the
|
||||
scheduler is suspended will not get placed in the ready
|
||||
list or removed from the blocked list until the scheduler
|
||||
is resumed.
|
||||
|
||||
This task cannot be in an event list as it is the currently
|
||||
executing task. */
|
||||
|
||||
/* Calculate the time to wake - this may overflow but this is
|
||||
not a problem. */
|
||||
xTimeToWake = xTickCount + xTicksToDelay;
|
||||
|
||||
/* We must remove ourselves from the ready list before adding
|
||||
ourselves to the blocked list as the same list item is used for
|
||||
both lists. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
|
||||
/* The list item will be inserted in wake time order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the
|
||||
overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the
|
||||
current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
xAlreadyYielded = xTaskResumeAll();
|
||||
}
|
||||
|
||||
/* Force a reschedule if xTaskResumeAll has not already done so, we may
|
||||
have put ourselves to sleep. */
|
||||
if( !xAlreadyYielded )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_uxTaskPriorityGet == 1 )
|
||||
|
||||
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
unsigned portBASE_TYPE uxReturn;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* If null is passed in here then we are changing the
|
||||
priority of the calling function. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTask );
|
||||
uxReturn = pxTCB->uxPriority;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskPrioritySet == 1 )
|
||||
|
||||
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
|
||||
|
||||
/* Ensure the new priority is valid. */
|
||||
if( uxNewPriority >= configMAX_PRIORITIES )
|
||||
{
|
||||
uxNewPriority = configMAX_PRIORITIES - 1;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( pxTask == pxCurrentTCB )
|
||||
{
|
||||
pxTask = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are changing the
|
||||
priority of the calling function. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTask );
|
||||
|
||||
traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
{
|
||||
uxCurrentPriority = pxTCB->uxBasePriority;
|
||||
}
|
||||
#else
|
||||
{
|
||||
uxCurrentPriority = pxTCB->uxPriority;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( uxCurrentPriority != uxNewPriority )
|
||||
{
|
||||
/* The priority change may have readied a task of higher
|
||||
priority than the calling task. */
|
||||
if( uxNewPriority > uxCurrentPriority )
|
||||
{
|
||||
if( pxTask != NULL )
|
||||
{
|
||||
/* The priority of another task is being raised. If we
|
||||
were raising the priority of the currently running task
|
||||
there would be no need to switch as it must have already
|
||||
been the highest priority task. */
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
}
|
||||
else if( pxTask == NULL )
|
||||
{
|
||||
/* Setting our own priority down means there may now be another
|
||||
task of higher priority that is ready to execute. */
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
{
|
||||
/* Only change the priority being used if the task is not
|
||||
currently using an inherited priority. */
|
||||
if( pxTCB->uxBasePriority == pxTCB->uxPriority )
|
||||
{
|
||||
pxTCB->uxPriority = uxNewPriority;
|
||||
}
|
||||
|
||||
/* The base priority gets set whatever. */
|
||||
pxTCB->uxBasePriority = uxNewPriority;
|
||||
}
|
||||
#else
|
||||
{
|
||||
pxTCB->uxPriority = uxNewPriority;
|
||||
}
|
||||
#endif
|
||||
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
|
||||
|
||||
/* If the task is in the blocked or suspended list we need do
|
||||
nothing more than change it's priority variable. However, if
|
||||
the task is in a ready list it needs to be removed and placed
|
||||
in the queue appropriate to its new priority. */
|
||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
|
||||
{
|
||||
/* The task is currently in its ready list - remove before adding
|
||||
it to it's new ready list. As we are in a critical section we
|
||||
can do this even if the scheduler is suspended. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
|
||||
if( xYieldRequired == pdTRUE )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
void vTaskSuspend( xTaskHandle pxTaskToSuspend )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* Ensure a yield is performed if the current task is being
|
||||
suspended. */
|
||||
if( pxTaskToSuspend == pxCurrentTCB )
|
||||
{
|
||||
pxTaskToSuspend = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are suspending ourselves. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
|
||||
|
||||
traceTASK_SUSPEND( pxTCB );
|
||||
|
||||
/* Remove task from the ready/delayed list and place in the suspended list. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Is the task waiting on an event also? */
|
||||
if( pxTCB->xEventListItem.pvContainer )
|
||||
{
|
||||
vListRemove( &( pxTCB->xEventListItem ) );
|
||||
}
|
||||
|
||||
vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* We may have just suspended the current task. */
|
||||
if( ( void * ) pxTaskToSuspend == NULL )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
|
||||
{
|
||||
portBASE_TYPE xReturn = pdFALSE;
|
||||
const tskTCB * const pxTCB = ( tskTCB * ) xTask;
|
||||
|
||||
/* Is the task we are attempting to resume actually in the
|
||||
suspended list? */
|
||||
if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
|
||||
{
|
||||
/* Has the task already been resumed from within an ISR? */
|
||||
if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
|
||||
{
|
||||
/* Is it in the suspended list because it is in the
|
||||
Suspended state? It is possible to be in the suspended
|
||||
list because it is blocked on a task with no timeout
|
||||
specified. */
|
||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
void vTaskResume( xTaskHandle pxTaskToResume )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
/* Remove the task from whichever list it is currently in, and place
|
||||
it in the ready list. */
|
||||
pxTCB = ( tskTCB * ) pxTaskToResume;
|
||||
|
||||
/* The parameter cannot be NULL as it is impossible to resume the
|
||||
currently executing task. */
|
||||
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
|
||||
{
|
||||
traceTASK_RESUME( pxTCB );
|
||||
|
||||
/* As we are in a critical section we can access the ready
|
||||
lists even if the scheduler is suspended. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
|
||||
/* We may have just resumed a higher priority task. */
|
||||
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* This yield may not cause the task just resumed to run, but
|
||||
will leave the lists in the correct state for the next yield. */
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
|
||||
|
||||
portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
|
||||
{
|
||||
portBASE_TYPE xYieldRequired = pdFALSE;
|
||||
tskTCB *pxTCB;
|
||||
|
||||
pxTCB = ( tskTCB * ) pxTaskToResume;
|
||||
|
||||
if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
|
||||
{
|
||||
traceTASK_RESUME_FROM_ISR( pxTCB );
|
||||
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We cannot access the delayed or ready lists, so will hold this
|
||||
task pending until the scheduler is resumed, at which point a
|
||||
yield will be performed if necessary. */
|
||||
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
|
||||
}
|
||||
}
|
||||
|
||||
return xYieldRequired;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* PUBLIC SCHEDULER CONTROL documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
void vTaskStartScheduler( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* Add the idle task at the lowest priority. */
|
||||
xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
|
||||
|
||||
if( xReturn == pdPASS )
|
||||
{
|
||||
/* Interrupts are turned off here, to ensure a tick does not occur
|
||||
before or during the call to xPortStartScheduler(). The stacks of
|
||||
the created tasks contain a status word with interrupts switched on
|
||||
so interrupts will automatically get re-enabled when the first task
|
||||
starts to run.
|
||||
|
||||
STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
|
||||
DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
xSchedulerRunning = pdTRUE;
|
||||
xTickCount = ( portTickType ) 0;
|
||||
|
||||
/* If configGENERATE_RUN_TIME_STATS is defined then the following
|
||||
macro must be defined to configure the timer/counter used to generate
|
||||
the run time counter time base. */
|
||||
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
|
||||
|
||||
/* Setting up the timer tick is hardware specific and thus in the
|
||||
portable interface. */
|
||||
if( xPortStartScheduler() )
|
||||
{
|
||||
/* Should not reach here as if the scheduler is running the
|
||||
function will not return. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Should only reach here if a task calls xTaskEndScheduler(). */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskEndScheduler( void )
|
||||
{
|
||||
/* Stop the scheduler interrupts and call the portable scheduler end
|
||||
routine so the original ISRs can be restored if necessary. The port
|
||||
layer must ensure interrupts enable bit is left in the correct state. */
|
||||
portDISABLE_INTERRUPTS();
|
||||
xSchedulerRunning = pdFALSE;
|
||||
vPortEndScheduler();
|
||||
}
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
void vTaskSuspendAll( void )
|
||||
{
|
||||
/* A critical section is not required as the variable is of type
|
||||
portBASE_TYPE. */
|
||||
++uxSchedulerSuspended;
|
||||
}
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xTaskResumeAll( void )
|
||||
{
|
||||
register tskTCB *pxTCB;
|
||||
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
|
||||
|
||||
/* It is possible that an ISR caused a task to be removed from an event
|
||||
list while the scheduler was suspended. If this was the case then the
|
||||
removed task will have been added to the xPendingReadyList. Once the
|
||||
scheduler has been resumed it is safe to move all the pending ready
|
||||
tasks from this list into their appropriate ready list. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
--uxSchedulerSuspended;
|
||||
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
portBASE_TYPE xYieldRequired = pdFALSE;
|
||||
|
||||
/* Move any readied tasks from the pending list into the
|
||||
appropriate ready list. */
|
||||
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
|
||||
{
|
||||
vListRemove( &( pxTCB->xEventListItem ) );
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
|
||||
/* If we have moved a task that has a priority higher than
|
||||
the current task then we should yield. */
|
||||
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
||||
{
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If any ticks occurred while the scheduler was suspended then
|
||||
they should be processed now. This ensures the tick count does not
|
||||
slip, and that any delayed tasks are resumed at the correct time. */
|
||||
if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
vTaskIncrementTick();
|
||||
--uxMissedTicks;
|
||||
}
|
||||
|
||||
/* As we have processed some ticks it is appropriate to yield
|
||||
to ensure the highest priority task that is ready to run is
|
||||
the task actually running. */
|
||||
#if configUSE_PREEMPTION == 1
|
||||
{
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
|
||||
{
|
||||
xAlreadyYielded = pdTRUE;
|
||||
xMissedYield = pdFALSE;
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xAlreadyYielded;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* PUBLIC TASK UTILITIES documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
portTickType xTaskGetTickCount( void )
|
||||
{
|
||||
portTickType xTicks;
|
||||
|
||||
/* Critical section required if running on a 16 bit processor. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
xTicks = xTickCount;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xTicks;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
|
||||
{
|
||||
/* A critical section is not required because the variables are of type
|
||||
portBASE_TYPE. */
|
||||
return uxCurrentNumberOfTasks;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
void vTaskList( signed char *pcWriteBuffer )
|
||||
{
|
||||
unsigned portBASE_TYPE uxQueue;
|
||||
|
||||
/* This is a VERY costly function that should be used for debug only.
|
||||
It leaves interrupts disabled for a LONG time. */
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Run through all the lists that could potentially contain a TCB and
|
||||
report the task name, state and stack high water mark. */
|
||||
|
||||
pcWriteBuffer[ 0 ] = ( signed char ) 0x00;
|
||||
strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
|
||||
|
||||
uxQueue = uxTopUsedPriority + 1;
|
||||
|
||||
do
|
||||
{
|
||||
uxQueue--;
|
||||
|
||||
if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
|
||||
}
|
||||
}while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
|
||||
}
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
|
||||
}
|
||||
|
||||
#if( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
||||
void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
|
||||
{
|
||||
unsigned portBASE_TYPE uxQueue;
|
||||
unsigned long ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
|
||||
|
||||
/* This is a VERY costly function that should be used for debug only.
|
||||
It leaves interrupts disabled for a LONG time. */
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Run through all the lists that could potentially contain a TCB,
|
||||
generating a table of run timer percentages in the provided
|
||||
buffer. */
|
||||
|
||||
pcWriteBuffer[ 0 ] = ( signed char ) 0x00;
|
||||
strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
|
||||
|
||||
uxQueue = uxTopUsedPriority + 1;
|
||||
|
||||
do
|
||||
{
|
||||
uxQueue--;
|
||||
|
||||
if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
|
||||
}
|
||||
}while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
|
||||
}
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
|
||||
}
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
pcTraceBuffer = ( signed char * )pcBuffer;
|
||||
pcTraceBufferStart = pcBuffer;
|
||||
pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
|
||||
xTracing = pdTRUE;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
unsigned long ulTaskEndTrace( void )
|
||||
{
|
||||
unsigned long ulBufferLength;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
xTracing = pdFALSE;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );
|
||||
|
||||
return ulBufferLength;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
|
||||
* documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
void vTaskIncrementTick( void )
|
||||
{
|
||||
/* Called by the portable layer each time a tick interrupt occurs.
|
||||
Increments the tick then checks to see if the new tick value will cause any
|
||||
tasks to be unblocked. */
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
++xTickCount;
|
||||
if( xTickCount == ( portTickType ) 0 )
|
||||
{
|
||||
xList *pxTemp;
|
||||
|
||||
/* Tick count has overflowed so we need to swap the delay lists.
|
||||
If there are any items in pxDelayedTaskList here then there is
|
||||
an error! */
|
||||
pxTemp = pxDelayedTaskList;
|
||||
pxDelayedTaskList = pxOverflowDelayedTaskList;
|
||||
pxOverflowDelayedTaskList = pxTemp;
|
||||
xNumOfOverflows++;
|
||||
}
|
||||
|
||||
/* See if this tick has made a timeout expire. */
|
||||
prvCheckDelayedTasks();
|
||||
}
|
||||
else
|
||||
{
|
||||
++uxMissedTicks;
|
||||
|
||||
/* The tick hook gets called at regular intervals, even if the
|
||||
scheduler is locked. */
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
{
|
||||
extern void vApplicationTickHook( void );
|
||||
|
||||
vApplicationTickHook();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
{
|
||||
extern void vApplicationTickHook( void );
|
||||
|
||||
/* Guard against the tick hook being called when the missed tick
|
||||
count is being unwound (when the scheduler is being unlocked. */
|
||||
if( uxMissedTicks == 0 )
|
||||
{
|
||||
vApplicationTickHook();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
traceTASK_INCREMENT_TICK( xTickCount );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
|
||||
|
||||
void vTaskCleanUpResources( void )
|
||||
{
|
||||
unsigned short usQueue;
|
||||
volatile tskTCB *pxTCB;
|
||||
|
||||
usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;
|
||||
|
||||
/* Remove any TCB's from the ready queues. */
|
||||
do
|
||||
{
|
||||
usQueue--;
|
||||
|
||||
while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
}while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );
|
||||
|
||||
/* Remove any TCB's from the delayed queue. */
|
||||
while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
|
||||
/* Remove any TCB's from the overflow delayed queue. */
|
||||
while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
|
||||
while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
|
||||
void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )
|
||||
{
|
||||
tskTCB *xTCB;
|
||||
|
||||
/* If xTask is NULL then we are setting our own task hook. */
|
||||
if( xTask == NULL )
|
||||
{
|
||||
xTCB = ( tskTCB * ) pxCurrentTCB;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTCB = ( tskTCB * ) xTask;
|
||||
}
|
||||
|
||||
/* Save the hook function in the TCB. A critical section is required as
|
||||
the value can be accessed from an interrupt. */
|
||||
portENTER_CRITICAL();
|
||||
xTCB->pxTaskTag = pxTagValue;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
|
||||
pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
|
||||
{
|
||||
tskTCB *xTCB;
|
||||
pdTASK_HOOK_CODE xReturn;
|
||||
|
||||
/* If xTask is NULL then we are setting our own task hook. */
|
||||
if( xTask == NULL )
|
||||
{
|
||||
xTCB = ( tskTCB * ) pxCurrentTCB;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTCB = ( tskTCB * ) xTask;
|
||||
}
|
||||
|
||||
/* Save the hook function in the TCB. A critical section is required as
|
||||
the value can be accessed from an interrupt. */
|
||||
portENTER_CRITICAL();
|
||||
xReturn = xTCB->pxTaskTag;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
|
||||
portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
|
||||
{
|
||||
tskTCB *xTCB;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* If xTask is NULL then we are calling our own task hook. */
|
||||
if( xTask == NULL )
|
||||
{
|
||||
xTCB = ( tskTCB * ) pxCurrentTCB;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTCB = ( tskTCB * ) xTask;
|
||||
}
|
||||
|
||||
if( xTCB->pxTaskTag != NULL )
|
||||
{
|
||||
xReturn = xTCB->pxTaskTag( pvParameter );
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskSwitchContext( void )
|
||||
{
|
||||
if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
/* The scheduler is currently suspended - do not allow a context
|
||||
switch. */
|
||||
xMissedYield = pdTRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
traceTASK_SWITCHED_OUT();
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
{
|
||||
unsigned long ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
|
||||
|
||||
/* Add the amount of time the task has been running to the accumulated
|
||||
time so far. The time the task started running was stored in
|
||||
ulTaskSwitchedInTime. Note that there is no overflow protection here
|
||||
so count values are only valid until the timer overflows. Generally
|
||||
this will be about 1 hour assuming a 1uS timer increment. */
|
||||
pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
|
||||
ulTaskSwitchedInTime = ulTempCounter;
|
||||
}
|
||||
#endif
|
||||
|
||||
taskFIRST_CHECK_FOR_STACK_OVERFLOW();
|
||||
taskSECOND_CHECK_FOR_STACK_OVERFLOW();
|
||||
|
||||
/* Find the highest priority queue that contains ready tasks. */
|
||||
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
|
||||
{
|
||||
--uxTopReadyPriority;
|
||||
}
|
||||
|
||||
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
|
||||
same priority get an equal share of the processor time. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
|
||||
|
||||
traceTASK_SWITCHED_IN();
|
||||
vWriteTraceToBuffer();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
|
||||
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
|
||||
SCHEDULER SUSPENDED. */
|
||||
|
||||
/* Place the event list item of the TCB in the appropriate event list.
|
||||
This is placed in the list in priority order so the highest priority task
|
||||
is the first to be woken by the event. */
|
||||
vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
|
||||
|
||||
/* We must remove ourselves from the ready list before adding ourselves
|
||||
to the blocked list as the same list item is used for both lists. We have
|
||||
exclusive access to the ready lists as the scheduler is locked. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
if( xTicksToWait == portMAX_DELAY )
|
||||
{
|
||||
/* Add ourselves to the suspended task list instead of a delayed task
|
||||
list to ensure we are not woken by a timing event. We will block
|
||||
indefinitely. */
|
||||
vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Calculate the time at which the task should be woken if the event does
|
||||
not occur. This may overflow but this doesn't matter. */
|
||||
xTimeToWake = xTickCount + xTicksToWait;
|
||||
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* Calculate the time at which the task should be woken if the event does
|
||||
not occur. This may overflow but this doesn't matter. */
|
||||
xTimeToWake = xTickCount + xTicksToWait;
|
||||
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
|
||||
{
|
||||
tskTCB *pxUnblockedTCB;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
|
||||
SCHEDULER SUSPENDED. It can also be called from within an ISR. */
|
||||
|
||||
/* The event list is sorted in priority order, so we can remove the
|
||||
first in the list, remove the TCB from the delayed list, and add
|
||||
it to the ready list.
|
||||
|
||||
If an event is for a queue that is locked then this function will never
|
||||
get called - the lock count on the queue will get modified instead. This
|
||||
means we can always expect exclusive access to the event list here. */
|
||||
pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
|
||||
vListRemove( &( pxUnblockedTCB->xEventListItem ) );
|
||||
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxUnblockedTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We cannot access the delayed or ready lists, so will hold this
|
||||
task pending until the scheduler is resumed. */
|
||||
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
|
||||
}
|
||||
|
||||
if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* Return true if the task removed from the event list has
|
||||
a higher priority than the calling task. This allows
|
||||
the calling task to know if it should force a context
|
||||
switch now. */
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
|
||||
{
|
||||
pxTimeOut->xOverflowCount = xNumOfOverflows;
|
||||
pxTimeOut->xTimeOnEntering = xTickCount;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
/* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
|
||||
the maximum block time then the task should block indefinitely, and
|
||||
therefore never time out. */
|
||||
if( *pxTicksToWait == portMAX_DELAY )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else /* We are not blocking indefinitely, perform the checks below. */
|
||||
#endif
|
||||
|
||||
if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
|
||||
{
|
||||
/* The tick count is greater than the time at which vTaskSetTimeout()
|
||||
was called, but has also overflowed since vTaskSetTimeOut() was called.
|
||||
It must have wrapped all the way around and gone past us again. This
|
||||
passed since vTaskSetTimeout() was called. */
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
|
||||
{
|
||||
/* Not a genuine timeout. Adjust parameters for time remaining. */
|
||||
*pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
|
||||
vTaskSetTimeOutState( pxTimeOut );
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskMissedYield( void )
|
||||
{
|
||||
xMissedYield = pdTRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* -----------------------------------------------------------
|
||||
* The Idle task.
|
||||
* ----------------------------------------------------------
|
||||
*
|
||||
* The portTASK_FUNCTION() macro is used to allow port/compiler specific
|
||||
* language extensions. The equivalent prototype for this function is:
|
||||
*
|
||||
* void prvIdleTask( void *pvParameters );
|
||||
*
|
||||
*/
|
||||
static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
||||
{
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* See if any tasks have been deleted. */
|
||||
prvCheckTasksWaitingTermination();
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
{
|
||||
/* If we are not using preemption we keep forcing a task switch to
|
||||
see if any other task has become available. If we are using
|
||||
preemption we don't need to do this as any task becoming available
|
||||
will automatically get the processor anyway. */
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
|
||||
{
|
||||
/* When using preemption tasks of equal priority will be
|
||||
timesliced. If a task that is sharing the idle priority is ready
|
||||
to run then the idle task should yield before the end of the
|
||||
timeslice.
|
||||
|
||||
A critical region is not required here as we are just reading from
|
||||
the list, and an occasional incorrect value will not matter. If
|
||||
the ready list at the idle priority contains more than one task
|
||||
then a task other than the idle task is ready to execute. */
|
||||
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( configUSE_IDLE_HOOK == 1 )
|
||||
{
|
||||
extern void vApplicationIdleHook( void );
|
||||
|
||||
/* Call the user defined function from within the idle task. This
|
||||
allows the application designer to add background functionality
|
||||
without the overhead of a separate task.
|
||||
NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
|
||||
CALL A FUNCTION THAT MIGHT BLOCK. */
|
||||
vApplicationIdleHook();
|
||||
}
|
||||
#endif
|
||||
// call nanosleep for smalles sleep time possible
|
||||
// (depending on kernel settings - around 100 microseconds)
|
||||
// decreases idle thread CPU load from 100 to practically 0
|
||||
struct timespec x;
|
||||
x.tv_sec=1;
|
||||
x.tv_nsec=0;
|
||||
nanosleep(&x,NULL);
|
||||
}
|
||||
} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* File private functions documented at the top of the file.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
|
||||
{
|
||||
/* Store the function name in the TCB. */
|
||||
#if configMAX_TASK_NAME_LEN > 1
|
||||
{
|
||||
/* Don't bring strncpy into the build unnecessarily. */
|
||||
strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
|
||||
}
|
||||
#endif
|
||||
pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = '\0';
|
||||
|
||||
/* This is used as an array index so must ensure it's not too large. First
|
||||
remove the privilege bit if one is present. */
|
||||
if( uxPriority >= configMAX_PRIORITIES )
|
||||
{
|
||||
uxPriority = configMAX_PRIORITIES - 1;
|
||||
}
|
||||
|
||||
pxTCB->uxPriority = uxPriority;
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
{
|
||||
pxTCB->uxBasePriority = uxPriority;
|
||||
}
|
||||
#endif
|
||||
|
||||
vListInitialiseItem( &( pxTCB->xGenericListItem ) );
|
||||
vListInitialiseItem( &( pxTCB->xEventListItem ) );
|
||||
|
||||
/* Set the pxTCB as a link back from the xListItem. This is so we can get
|
||||
back to the containing TCB from a generic item in a list. */
|
||||
listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
|
||||
|
||||
/* Event lists are always in priority order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
|
||||
listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
{
|
||||
pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
{
|
||||
pxTCB->pxTaskTag = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
{
|
||||
pxTCB->ulRunTimeCounter = 0UL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
{
|
||||
vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
|
||||
}
|
||||
#else
|
||||
{
|
||||
( void ) xRegions;
|
||||
( void ) usStackDepth;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
|
||||
void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
if( xTaskToModify == pxCurrentTCB )
|
||||
{
|
||||
xTaskToModify = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are deleting ourselves. */
|
||||
pxTCB = prvGetTCBFromHandle( xTaskToModify );
|
||||
|
||||
vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
#endif
|
||||
|
||||
static void prvInitialiseTaskLists( void )
|
||||
{
|
||||
unsigned portBASE_TYPE uxPriority;
|
||||
|
||||
for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
|
||||
{
|
||||
vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
|
||||
}
|
||||
|
||||
vListInitialise( ( xList * ) &xDelayedTaskList1 );
|
||||
vListInitialise( ( xList * ) &xDelayedTaskList2 );
|
||||
vListInitialise( ( xList * ) &xPendingReadyList );
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
vListInitialise( ( xList * ) &xTasksWaitingTermination );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
vListInitialise( ( xList * ) &xSuspendedTaskList );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
|
||||
using list2. */
|
||||
pxDelayedTaskList = &xDelayedTaskList1;
|
||||
pxOverflowDelayedTaskList = &xDelayedTaskList2;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckTasksWaitingTermination( void )
|
||||
{
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
portBASE_TYPE xListIsEmpty;
|
||||
|
||||
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
|
||||
too often in the idle task. */
|
||||
if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
|
||||
xTaskResumeAll();
|
||||
|
||||
if( !xListIsEmpty )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
--uxCurrentNumberOfTasks;
|
||||
--uxTasksDeleted;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
prvDeleteTCB( pxTCB );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
|
||||
{
|
||||
tskTCB *pxNewTCB;
|
||||
|
||||
/* Allocate space for the TCB. Where the memory comes from depends on
|
||||
the implementation of the port malloc function. */
|
||||
pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
|
||||
|
||||
if( pxNewTCB != NULL )
|
||||
{
|
||||
/* Allocate space for the stack used by the task being created.
|
||||
The base of the stack memory stored in the TCB so the task can
|
||||
be deleted later if required. */
|
||||
pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
|
||||
|
||||
if( pxNewTCB->pxStack == NULL )
|
||||
{
|
||||
/* Could not allocate the stack. Delete the allocated TCB. */
|
||||
vPortFree( pxNewTCB );
|
||||
pxNewTCB = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just to help debugging. */
|
||||
memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
|
||||
}
|
||||
}
|
||||
|
||||
return pxNewTCB;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
|
||||
{
|
||||
volatile tskTCB *pxNextTCB, *pxFirstTCB;
|
||||
unsigned short usStackRemaining;
|
||||
|
||||
/* Write the details of all the TCB's in pxList into the buffer. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
|
||||
do
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
|
||||
#if ( portSTACK_GROWTH > 0 )
|
||||
{
|
||||
usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
|
||||
}
|
||||
#else
|
||||
{
|
||||
usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
|
||||
}
|
||||
#endif
|
||||
|
||||
sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
|
||||
strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
|
||||
|
||||
} while( pxNextTCB != pxFirstTCB );
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
||||
static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )
|
||||
{
|
||||
volatile tskTCB *pxNextTCB, *pxFirstTCB;
|
||||
unsigned long ulStatsAsPercentage;
|
||||
|
||||
/* Write the run time stats of all the TCB's in pxList into the buffer. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
|
||||
do
|
||||
{
|
||||
/* Get next TCB in from the list. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
|
||||
|
||||
/* Divide by zero check. */
|
||||
if( ulTotalRunTime > 0UL )
|
||||
{
|
||||
/* Has the task run at all? */
|
||||
if( pxNextTCB->ulRunTimeCounter == 0 )
|
||||
{
|
||||
/* The task has used no CPU time at all. */
|
||||
sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* What percentage of the total run time as the task used?
|
||||
This will always be rounded down to the nearest integer. */
|
||||
ulStatsAsPercentage = ( 100UL * pxNextTCB->ulRunTimeCounter ) / ulTotalRunTime;
|
||||
|
||||
if( ulStatsAsPercentage > 0UL )
|
||||
{
|
||||
sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the percentage is zero here then the task has
|
||||
consumed less than 1% of the total run time. */
|
||||
sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
|
||||
}
|
||||
}
|
||||
|
||||
strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );
|
||||
}
|
||||
|
||||
} while( pxNextTCB != pxFirstTCB );
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
||||
|
||||
static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
|
||||
{
|
||||
register unsigned short usCount = 0;
|
||||
|
||||
while( *pucStackByte == tskSTACK_FILL_BYTE )
|
||||
{
|
||||
pucStackByte -= portSTACK_GROWTH;
|
||||
usCount++;
|
||||
}
|
||||
|
||||
usCount /= sizeof( portSTACK_TYPE );
|
||||
|
||||
return usCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
|
||||
|
||||
unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
unsigned char *pcEndOfStack;
|
||||
unsigned portBASE_TYPE uxReturn;
|
||||
|
||||
pxTCB = prvGetTCBFromHandle( xTask );
|
||||
|
||||
#if portSTACK_GROWTH < 0
|
||||
{
|
||||
pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
|
||||
}
|
||||
#else
|
||||
{
|
||||
pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
|
||||
}
|
||||
#endif
|
||||
|
||||
uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
|
||||
|
||||
static void prvDeleteTCB( tskTCB *pxTCB )
|
||||
{
|
||||
/* Free up the memory allocated by the scheduler for the task. It is up to
|
||||
the task to free any memory allocated at the application level. */
|
||||
vPortFreeAligned( pxTCB->pxStack );
|
||||
vPortFree( pxTCB );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
|
||||
|
||||
xTaskHandle xTaskGetCurrentTaskHandle( void )
|
||||
{
|
||||
xTaskHandle xReturn;
|
||||
|
||||
/* A critical section is not required as this is not called from
|
||||
an interrupt and the current TCB will always be the same for any
|
||||
individual execution thread. */
|
||||
xReturn = pxCurrentTCB;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_xTaskGetSchedulerState == 1 )
|
||||
|
||||
portBASE_TYPE xTaskGetSchedulerState( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
if( xSchedulerRunning == pdFALSE )
|
||||
{
|
||||
xReturn = taskSCHEDULER_NOT_STARTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
xReturn = taskSCHEDULER_RUNNING;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = taskSCHEDULER_SUSPENDED;
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
|
||||
void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
|
||||
{
|
||||
tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
|
||||
|
||||
if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* Adjust the mutex holder state to account for its new priority. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
|
||||
|
||||
/* If the task being modified is in the ready state it will need to
|
||||
be moved in to a new list. */
|
||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
|
||||
{
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Inherit the priority before being moved into the new list. */
|
||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just inherit the priority. */
|
||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
|
||||
void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
|
||||
{
|
||||
tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
|
||||
|
||||
if( pxMutexHolder != NULL )
|
||||
{
|
||||
if( pxTCB->uxPriority != pxTCB->uxBasePriority )
|
||||
{
|
||||
/* We must be the running task to be able to give the mutex back.
|
||||
Remove ourselves from the ready list we currently appear in. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Disinherit the priority before adding ourselves into the new
|
||||
ready list. */
|
||||
pxTCB->uxPriority = pxTCB->uxBasePriority;
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
||||
void vTaskEnterCritical( void )
|
||||
{
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
pxCurrentTCB->uxCriticalNesting++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
||||
void vTaskExitCritical( void )
|
||||
{
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
if( pxCurrentTCB->uxCriticalNesting > 0 )
|
||||
{
|
||||
pxCurrentTCB->uxCriticalNesting--;
|
||||
|
||||
if( pxCurrentTCB->uxCriticalNesting == 0 )
|
||||
{
|
||||
portENABLE_INTERRUPTS();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
FreeRTOS V6.0.4 - Copyright (C) 2010 Real Time Engineers Ltd.
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* If you are: *
|
||||
* *
|
||||
* + New to FreeRTOS, *
|
||||
* + Wanting to learn FreeRTOS or multitasking in general quickly *
|
||||
* + Looking for basic training, *
|
||||
* + Wanting to improve your FreeRTOS skills and productivity *
|
||||
* *
|
||||
* then take a look at the FreeRTOS eBook *
|
||||
* *
|
||||
* "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
* A pdf reference manual is also available. Both are usually delivered *
|
||||
* to your inbox within 20 minutes to two hours when purchased between 8am *
|
||||
* and 8pm GMT (although please allow up to 24 hours in case of *
|
||||
* exceptional circumstances). Thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
***NOTE*** The exception to the GPL is included to allow you to distribute
|
||||
a combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details. You should have received a copy of the GNU General Public
|
||||
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "StackMacros.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
/*
|
||||
* Macro to define the amount of stack available to the idle task.
|
||||
*/
|
||||
#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/*
|
||||
* Task control block. A task control block (TCB) is allocated to each task,
|
||||
* and stores the context of the task.
|
||||
*/
|
||||
typedef struct tskTaskControlBlock
|
||||
{
|
||||
volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
|
||||
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
|
||||
#endif
|
||||
|
||||
xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
|
||||
xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
|
||||
unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
|
||||
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
|
||||
signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
|
||||
|
||||
#if ( portSTACK_GROWTH > 0 )
|
||||
portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
|
||||
#endif
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
unsigned portBASE_TYPE uxCriticalNesting;
|
||||
#endif
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
|
||||
#endif
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
|
||||
#endif
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
pdTASK_HOOK_CODE pxTaskTag;
|
||||
#endif
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
|
||||
#endif
|
||||
|
||||
} tskTCB;
|
||||
|
||||
|
||||
/*
|
||||
* Some kernel aware debuggers require data to be viewed to be global, rather
|
||||
* than file scope.
|
||||
*/
|
||||
#ifdef portREMOVE_STATIC_QUALIFIER
|
||||
#define static
|
||||
#endif
|
||||
|
||||
/*lint -e956 */
|
||||
PRIVILEGED_DATA tskTCB * volatile pxCurrentTCB = NULL;
|
||||
|
||||
/* Lists for ready and blocked tasks. --------------------*/
|
||||
|
||||
PRIVILEGED_DATA static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
|
||||
PRIVILEGED_DATA static xList xDelayedTaskList1; /*< Delayed tasks. */
|
||||
PRIVILEGED_DATA static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
|
||||
PRIVILEGED_DATA static xList * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
|
||||
PRIVILEGED_DATA static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
|
||||
PRIVILEGED_DATA static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
|
||||
PRIVILEGED_DATA static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
|
||||
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
PRIVILEGED_DATA static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
|
||||
|
||||
#endif
|
||||
|
||||
/* File private variables. --------------------------------*/
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
|
||||
PRIVILEGED_DATA static volatile portTickType xTickCount = ( portTickType ) 0;
|
||||
PRIVILEGED_DATA static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
|
||||
PRIVILEGED_DATA static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
|
||||
PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
|
||||
PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
|
||||
PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
|
||||
PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0;
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
||||
PRIVILEGED_DATA static char pcStatsString[ 50 ] ;
|
||||
PRIVILEGED_DATA static unsigned long ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
|
||||
static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
/* Debugging and trace facilities private variables and macros. ------------*/
|
||||
|
||||
/*
|
||||
* The value used to fill the stack of a task when the task is created. This
|
||||
* is used purely for checking the high water mark for tasks.
|
||||
*/
|
||||
#define tskSTACK_FILL_BYTE ( 0xa5 )
|
||||
|
||||
/*
|
||||
* Macros used by vListTask to indicate which state a task is in.
|
||||
*/
|
||||
#define tskBLOCKED_CHAR ( ( signed char ) 'B' )
|
||||
#define tskREADY_CHAR ( ( signed char ) 'R' )
|
||||
#define tskDELETED_CHAR ( ( signed char ) 'D' )
|
||||
#define tskSUSPENDED_CHAR ( ( signed char ) 'S' )
|
||||
|
||||
/*
|
||||
* Macros and private variables used by the trace facility.
|
||||
*/
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
#define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned long ) ( sizeof( unsigned long ) + sizeof( unsigned long ) ) )
|
||||
PRIVILEGED_DATA static volatile signed char * volatile pcTraceBuffer;
|
||||
PRIVILEGED_DATA static signed char *pcTraceBufferStart;
|
||||
PRIVILEGED_DATA static signed char *pcTraceBufferEnd;
|
||||
PRIVILEGED_DATA static signed portBASE_TYPE xTracing = pdFALSE;
|
||||
static unsigned portBASE_TYPE uxPreviousTask = 255;
|
||||
PRIVILEGED_DATA static char pcStatusString[ 50 ];
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Macro that writes a trace of scheduler activity to a buffer. This trace
|
||||
* shows which task is running when and is very useful as a debugging tool.
|
||||
* As this macro is called each context switch it is a good idea to undefine
|
||||
* it if not using the facility.
|
||||
*/
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
#define vWriteTraceToBuffer() \
|
||||
{ \
|
||||
if( xTracing ) \
|
||||
{ \
|
||||
if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
|
||||
{ \
|
||||
if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
|
||||
{ \
|
||||
uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
|
||||
*( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \
|
||||
pcTraceBuffer += sizeof( unsigned long ); \
|
||||
*( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \
|
||||
pcTraceBuffer += sizeof( unsigned long ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
xTracing = pdFALSE; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define vWriteTraceToBuffer()
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Place the task represented by pxTCB into the appropriate ready queue for
|
||||
* the task. It is inserted at the end of the list. One quirk of this is
|
||||
* that if the task being inserted is at the same priority as the currently
|
||||
* executing task, then it will only be rescheduled after the currently
|
||||
* executing task has been rescheduled.
|
||||
*/
|
||||
#define prvAddTaskToReadyQueue( pxTCB ) \
|
||||
{ \
|
||||
if( pxTCB->uxPriority > uxTopReadyPriority ) \
|
||||
{ \
|
||||
uxTopReadyPriority = pxTCB->uxPriority; \
|
||||
} \
|
||||
vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Macro that looks at the list of tasks that are currently delayed to see if
|
||||
* any require waking.
|
||||
*
|
||||
* Tasks are stored in the queue in the order of their wake time - meaning
|
||||
* once one tasks has been found whose timer has not expired we need not look
|
||||
* any further down the list.
|
||||
*/
|
||||
#define prvCheckDelayedTasks() \
|
||||
{ \
|
||||
register tskTCB *pxTCB; \
|
||||
\
|
||||
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
|
||||
{ \
|
||||
if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
|
||||
{ \
|
||||
break; \
|
||||
} \
|
||||
vListRemove( &( pxTCB->xGenericListItem ) ); \
|
||||
/* Is the task waiting on an event also? */ \
|
||||
if( pxTCB->xEventListItem.pvContainer ) \
|
||||
{ \
|
||||
vListRemove( &( pxTCB->xEventListItem ) ); \
|
||||
} \
|
||||
prvAddTaskToReadyQueue( pxTCB ); \
|
||||
} \
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Several functions take an xTaskHandle parameter that can optionally be NULL,
|
||||
* where NULL is used to indicate that the handle of the currently executing
|
||||
* task should be used in place of the parameter. This macro simply checks to
|
||||
* see if the parameter is NULL and returns a pointer to the appropriate TCB.
|
||||
*/
|
||||
#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
|
||||
|
||||
|
||||
/* File private functions. --------------------------------*/
|
||||
|
||||
/*
|
||||
* Utility to ready a TCB for a given task. Mainly just copies the parameters
|
||||
* into the TCB structure.
|
||||
*/
|
||||
static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Utility to ready all the lists used by the scheduler. This is called
|
||||
* automatically upon the creation of the first task.
|
||||
*/
|
||||
static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* The idle task, which as all tasks is implemented as a never ending loop.
|
||||
* The idle task is automatically created and added to the ready lists upon
|
||||
* creation of the first user task.
|
||||
*
|
||||
* The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
|
||||
* language extensions. The equivalent prototype for this function is:
|
||||
*
|
||||
* void prvIdleTask( void *pvParameters );
|
||||
*
|
||||
*/
|
||||
static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
|
||||
|
||||
/*
|
||||
* Utility to free all memory allocated by the scheduler to hold a TCB,
|
||||
* including the stack pointed to by the TCB.
|
||||
*
|
||||
* This does not free memory allocated by the task itself (i.e. memory
|
||||
* allocated by calls to pvPortMalloc from within the tasks application code).
|
||||
*/
|
||||
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
|
||||
|
||||
static void prvDeleteTCB( tskTCB *pxTCB ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used only by the idle task. This checks to see if anything has been placed
|
||||
* in the list of tasks waiting to be deleted. If so the task is cleaned up
|
||||
* and its TCB deleted.
|
||||
*/
|
||||
static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Allocates memory from the heap for a TCB and associated stack. Checks the
|
||||
* allocation was successful.
|
||||
*/
|
||||
static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Called from vTaskList. vListTasks details all the tasks currently under
|
||||
* control of the scheduler. The tasks may be in one of a number of lists.
|
||||
* prvListTaskWithinSingleList accepts a list and details the tasks from
|
||||
* within just that list.
|
||||
*
|
||||
* THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
|
||||
* NORMAL APPLICATION CODE.
|
||||
*/
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When a task is created, the stack of the task is filled with a known value.
|
||||
* This function determines the 'high water mark' of the task stack by
|
||||
* determining how much of the stack remains at the original preset value.
|
||||
*/
|
||||
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
||||
|
||||
static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*lint +e956 */
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* TASK CREATION API documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions )
|
||||
{
|
||||
signed portBASE_TYPE xReturn;
|
||||
tskTCB * pxNewTCB;
|
||||
|
||||
/* Allocate the memory required by the TCB and stack for the new task,
|
||||
checking that the allocation was successful. */
|
||||
pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
|
||||
|
||||
if( pxNewTCB != NULL )
|
||||
{
|
||||
portSTACK_TYPE *pxTopOfStack;
|
||||
|
||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||
/* Should the task be created in privileged mode? */
|
||||
portBASE_TYPE xRunPrivileged;
|
||||
if( ( uxPriority & portPRIVILEGE_BIT ) != 0x00 )
|
||||
{
|
||||
xRunPrivileged = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xRunPrivileged = pdFALSE;
|
||||
}
|
||||
uxPriority &= ~portPRIVILEGE_BIT;
|
||||
#endif /* portUSING_MPU_WRAPPERS == 1 */
|
||||
|
||||
/* Calculate the top of stack address. This depends on whether the
|
||||
stack grows from high memory to low (as per the 80x86) or visa versa.
|
||||
portSTACK_GROWTH is used to make the result positive or negative as
|
||||
required by the port. */
|
||||
#if( portSTACK_GROWTH < 0 )
|
||||
{
|
||||
pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
|
||||
pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( unsigned long ) pxTopOfStack ) & ( ( unsigned long ) ~portBYTE_ALIGNMENT_MASK ) );
|
||||
}
|
||||
#else
|
||||
{
|
||||
pxTopOfStack = pxNewTCB->pxStack;
|
||||
|
||||
/* If we want to use stack checking on architectures that use
|
||||
a positive stack growth direction then we also need to store the
|
||||
other extreme of the stack space. */
|
||||
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup the newly allocated TCB with the initial state of the task. */
|
||||
prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth );
|
||||
|
||||
/* Initialize the TCB stack to look as if the task was already running,
|
||||
but had been interrupted by the scheduler. The return address is set
|
||||
to the start of the task function. Once the stack has been initialised
|
||||
the top of stack variable is updated. */
|
||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||
{
|
||||
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
|
||||
}
|
||||
#else
|
||||
{
|
||||
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We are going to manipulate the task queues to add this task to a
|
||||
ready list, so must make sure no interrupts occur. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxCurrentNumberOfTasks++;
|
||||
if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
|
||||
{
|
||||
/* As this is the first task it must also be the current task. */
|
||||
pxCurrentTCB = pxNewTCB;
|
||||
|
||||
/* This is the first task to be created so do the preliminary
|
||||
initialisation required. We will not recover if this call
|
||||
fails, but we will report the failure. */
|
||||
prvInitialiseTaskLists();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the scheduler is not already running, make this task the
|
||||
current task if it is the highest priority task to be created
|
||||
so far. */
|
||||
if( xSchedulerRunning == pdFALSE )
|
||||
{
|
||||
if( pxCurrentTCB->uxPriority <= uxPriority )
|
||||
{
|
||||
pxCurrentTCB = pxNewTCB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember the top priority to make context switching faster. Use
|
||||
the priority in pxNewTCB as this has been capped to a valid value. */
|
||||
if( pxNewTCB->uxPriority > uxTopUsedPriority )
|
||||
{
|
||||
uxTopUsedPriority = pxNewTCB->uxPriority;
|
||||
}
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
{
|
||||
/* Add a counter into the TCB for tracing only. */
|
||||
pxNewTCB->uxTCBNumber = uxTaskNumber;
|
||||
}
|
||||
#endif
|
||||
uxTaskNumber++;
|
||||
|
||||
prvAddTaskToReadyQueue( pxNewTCB );
|
||||
|
||||
xReturn = pdPASS;
|
||||
traceTASK_CREATE( pxNewTCB );
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
||||
traceTASK_CREATE_FAILED( pxNewTCB );
|
||||
}
|
||||
|
||||
if( xReturn == pdPASS )
|
||||
{
|
||||
if( ( void * ) pxCreatedTask != NULL )
|
||||
{
|
||||
/* Pass the TCB out - in an anonymous way. The calling function/
|
||||
task can use this as a handle to delete the task later if
|
||||
required.*/
|
||||
*pxCreatedTask = ( xTaskHandle ) pxNewTCB;
|
||||
}
|
||||
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
/* If the created task is of a higher priority than the current task
|
||||
then it should run now. */
|
||||
if( pxCurrentTCB->uxPriority < uxPriority )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
|
||||
void vTaskDelete( xTaskHandle pxTaskToDelete )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* Ensure a yield is performed if the current task is being
|
||||
deleted. */
|
||||
if( pxTaskToDelete == pxCurrentTCB )
|
||||
{
|
||||
pxTaskToDelete = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are deleting ourselves. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
|
||||
|
||||
/* Remove task from the ready list and place in the termination list.
|
||||
This will stop the task from be scheduled. The idle task will check
|
||||
the termination list and free up any memory allocated by the
|
||||
scheduler for the TCB and stack. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Is the task waiting on an event also? */
|
||||
if( pxTCB->xEventListItem.pvContainer )
|
||||
{
|
||||
vListRemove( &( pxTCB->xEventListItem ) );
|
||||
}
|
||||
|
||||
vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Increment the ucTasksDeleted variable so the idle task knows
|
||||
there is a task that has been deleted and that it should therefore
|
||||
check the xTasksWaitingTermination list. */
|
||||
++uxTasksDeleted;
|
||||
|
||||
/* Increment the uxTaskNumberVariable also so kernel aware debuggers
|
||||
can detect that the task lists need re-generating. */
|
||||
uxTaskNumber++;
|
||||
|
||||
traceTASK_DELETE( pxTCB );
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Force a reschedule if we have just deleted the current task. */
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
if( ( void * ) pxTaskToDelete == NULL )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* TASK CONTROL API documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskDelayUntil == 1 )
|
||||
|
||||
void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Generate the tick time at which the task wants to wake. */
|
||||
xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
|
||||
|
||||
if( xTickCount < *pxPreviousWakeTime )
|
||||
{
|
||||
/* The tick count has overflowed since this function was
|
||||
lasted called. In this case the only time we should ever
|
||||
actually delay is if the wake time has also overflowed,
|
||||
and the wake time is greater than the tick time. When this
|
||||
is the case it is as if neither time had overflowed. */
|
||||
if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
|
||||
{
|
||||
xShouldDelay = pdTRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The tick time has not overflowed. In this case we will
|
||||
delay if either the wake time has overflowed, and/or the
|
||||
tick time is less than the wake time. */
|
||||
if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
|
||||
{
|
||||
xShouldDelay = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the wake time ready for the next call. */
|
||||
*pxPreviousWakeTime = xTimeToWake;
|
||||
|
||||
if( xShouldDelay )
|
||||
{
|
||||
traceTASK_DELAY_UNTIL();
|
||||
|
||||
/* We must remove ourselves from the ready list before adding
|
||||
ourselves to the blocked list as the same list item is used for
|
||||
both lists. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
|
||||
/* The list item will be inserted in wake time order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the
|
||||
overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the
|
||||
current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
xAlreadyYielded = xTaskResumeAll();
|
||||
|
||||
/* Force a reschedule if xTaskResumeAll has not already done so, we may
|
||||
have put ourselves to sleep. */
|
||||
if( !xAlreadyYielded )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskDelay == 1 )
|
||||
|
||||
void vTaskDelay( portTickType xTicksToDelay )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
|
||||
|
||||
/* A delay time of zero just forces a reschedule. */
|
||||
if( xTicksToDelay > ( portTickType ) 0 )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
traceTASK_DELAY();
|
||||
|
||||
/* A task that is removed from the event list while the
|
||||
scheduler is suspended will not get placed in the ready
|
||||
list or removed from the blocked list until the scheduler
|
||||
is resumed.
|
||||
|
||||
This task cannot be in an event list as it is the currently
|
||||
executing task. */
|
||||
|
||||
/* Calculate the time to wake - this may overflow but this is
|
||||
not a problem. */
|
||||
xTimeToWake = xTickCount + xTicksToDelay;
|
||||
|
||||
/* We must remove ourselves from the ready list before adding
|
||||
ourselves to the blocked list as the same list item is used for
|
||||
both lists. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
|
||||
/* The list item will be inserted in wake time order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the
|
||||
overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the
|
||||
current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
xAlreadyYielded = xTaskResumeAll();
|
||||
}
|
||||
|
||||
/* Force a reschedule if xTaskResumeAll has not already done so, we may
|
||||
have put ourselves to sleep. */
|
||||
if( !xAlreadyYielded )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_uxTaskPriorityGet == 1 )
|
||||
|
||||
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
unsigned portBASE_TYPE uxReturn;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* If null is passed in here then we are changing the
|
||||
priority of the calling function. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTask );
|
||||
uxReturn = pxTCB->uxPriority;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskPrioritySet == 1 )
|
||||
|
||||
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
|
||||
|
||||
/* Ensure the new priority is valid. */
|
||||
if( uxNewPriority >= configMAX_PRIORITIES )
|
||||
{
|
||||
uxNewPriority = configMAX_PRIORITIES - 1;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( pxTask == pxCurrentTCB )
|
||||
{
|
||||
pxTask = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are changing the
|
||||
priority of the calling function. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTask );
|
||||
|
||||
traceTASK_PRIORITY_SET( pxTask, uxNewPriority );
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
{
|
||||
uxCurrentPriority = pxTCB->uxBasePriority;
|
||||
}
|
||||
#else
|
||||
{
|
||||
uxCurrentPriority = pxTCB->uxPriority;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( uxCurrentPriority != uxNewPriority )
|
||||
{
|
||||
/* The priority change may have readied a task of higher
|
||||
priority than the calling task. */
|
||||
if( uxNewPriority > uxCurrentPriority )
|
||||
{
|
||||
if( pxTask != NULL )
|
||||
{
|
||||
/* The priority of another task is being raised. If we
|
||||
were raising the priority of the currently running task
|
||||
there would be no need to switch as it must have already
|
||||
been the highest priority task. */
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
}
|
||||
else if( pxTask == NULL )
|
||||
{
|
||||
/* Setting our own priority down means there may now be another
|
||||
task of higher priority that is ready to execute. */
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
{
|
||||
/* Only change the priority being used if the task is not
|
||||
currently using an inherited priority. */
|
||||
if( pxTCB->uxBasePriority == pxTCB->uxPriority )
|
||||
{
|
||||
pxTCB->uxPriority = uxNewPriority;
|
||||
}
|
||||
|
||||
/* The base priority gets set whatever. */
|
||||
pxTCB->uxBasePriority = uxNewPriority;
|
||||
}
|
||||
#else
|
||||
{
|
||||
pxTCB->uxPriority = uxNewPriority;
|
||||
}
|
||||
#endif
|
||||
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( configMAX_PRIORITIES - ( portTickType ) uxNewPriority ) );
|
||||
|
||||
/* If the task is in the blocked or suspended list we need do
|
||||
nothing more than change it's priority variable. However, if
|
||||
the task is in a ready list it needs to be removed and placed
|
||||
in the queue appropriate to its new priority. */
|
||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
|
||||
{
|
||||
/* The task is currently in its ready list - remove before adding
|
||||
it to it's new ready list. As we are in a critical section we
|
||||
can do this even if the scheduler is suspended. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
|
||||
if( xYieldRequired == pdTRUE )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
void vTaskSuspend( xTaskHandle pxTaskToSuspend )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* Ensure a yield is performed if the current task is being
|
||||
suspended. */
|
||||
if( pxTaskToSuspend == pxCurrentTCB )
|
||||
{
|
||||
pxTaskToSuspend = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are suspending ourselves. */
|
||||
pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
|
||||
|
||||
traceTASK_SUSPEND( pxTCB );
|
||||
|
||||
/* Remove task from the ready/delayed list and place in the suspended list. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Is the task waiting on an event also? */
|
||||
if( pxTCB->xEventListItem.pvContainer )
|
||||
{
|
||||
vListRemove( &( pxTCB->xEventListItem ) );
|
||||
}
|
||||
|
||||
vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* We may have just suspended the current task. */
|
||||
if( ( void * ) pxTaskToSuspend == NULL )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
signed portBASE_TYPE xTaskIsTaskSuspended( xTaskHandle xTask )
|
||||
{
|
||||
portBASE_TYPE xReturn = pdFALSE;
|
||||
const tskTCB * const pxTCB = ( tskTCB * ) xTask;
|
||||
|
||||
/* Is the task we are attempting to resume actually in the
|
||||
suspended list? */
|
||||
if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
|
||||
{
|
||||
/* Has the task already been resumed from within an ISR? */
|
||||
if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
|
||||
{
|
||||
/* Is it in the suspended list because it is in the
|
||||
Suspended state? It is possible to be in the suspended
|
||||
list because it is blocked on a task with no timeout
|
||||
specified. */
|
||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
|
||||
void vTaskResume( xTaskHandle pxTaskToResume )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
/* Remove the task from whichever list it is currently in, and place
|
||||
it in the ready list. */
|
||||
pxTCB = ( tskTCB * ) pxTaskToResume;
|
||||
|
||||
/* The parameter cannot be NULL as it is impossible to resume the
|
||||
currently executing task. */
|
||||
if( ( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB ) )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
|
||||
{
|
||||
traceTASK_RESUME( pxTCB );
|
||||
|
||||
/* As we are in a critical section we can access the ready
|
||||
lists even if the scheduler is suspended. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
|
||||
/* We may have just resumed a higher priority task. */
|
||||
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* This yield may not cause the task just resumed to run, but
|
||||
will leave the lists in the correct state for the next yield. */
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
|
||||
|
||||
portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
|
||||
{
|
||||
portBASE_TYPE xYieldRequired = pdFALSE;
|
||||
tskTCB *pxTCB;
|
||||
|
||||
pxTCB = ( tskTCB * ) pxTaskToResume;
|
||||
|
||||
if( xTaskIsTaskSuspended( pxTCB ) == pdTRUE )
|
||||
{
|
||||
traceTASK_RESUME_FROM_ISR( pxTCB );
|
||||
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We cannot access the delayed or ready lists, so will hold this
|
||||
task pending until the scheduler is resumed, at which point a
|
||||
yield will be performed if necessary. */
|
||||
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
|
||||
}
|
||||
}
|
||||
|
||||
return xYieldRequired;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* PUBLIC SCHEDULER CONTROL documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
void vTaskStartScheduler( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* Add the idle task at the lowest priority. */
|
||||
xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
|
||||
|
||||
if( xReturn == pdPASS )
|
||||
{
|
||||
/* Interrupts are turned off here, to ensure a tick does not occur
|
||||
before or during the call to xPortStartScheduler(). The stacks of
|
||||
the created tasks contain a status word with interrupts switched on
|
||||
so interrupts will automatically get re-enabled when the first task
|
||||
starts to run.
|
||||
|
||||
STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
|
||||
DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
xSchedulerRunning = pdTRUE;
|
||||
xTickCount = ( portTickType ) 0;
|
||||
|
||||
/* If configGENERATE_RUN_TIME_STATS is defined then the following
|
||||
macro must be defined to configure the timer/counter used to generate
|
||||
the run time counter time base. */
|
||||
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
|
||||
|
||||
/* Setting up the timer tick is hardware specific and thus in the
|
||||
portable interface. */
|
||||
if( xPortStartScheduler() )
|
||||
{
|
||||
/* Should not reach here as if the scheduler is running the
|
||||
function will not return. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Should only reach here if a task calls xTaskEndScheduler(). */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskEndScheduler( void )
|
||||
{
|
||||
/* Stop the scheduler interrupts and call the portable scheduler end
|
||||
routine so the original ISRs can be restored if necessary. The port
|
||||
layer must ensure interrupts enable bit is left in the correct state. */
|
||||
portDISABLE_INTERRUPTS();
|
||||
xSchedulerRunning = pdFALSE;
|
||||
vPortEndScheduler();
|
||||
}
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
void vTaskSuspendAll( void )
|
||||
{
|
||||
/* A critical section is not required as the variable is of type
|
||||
portBASE_TYPE. */
|
||||
++uxSchedulerSuspended;
|
||||
}
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xTaskResumeAll( void )
|
||||
{
|
||||
register tskTCB *pxTCB;
|
||||
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
|
||||
|
||||
/* It is possible that an ISR caused a task to be removed from an event
|
||||
list while the scheduler was suspended. If this was the case then the
|
||||
removed task will have been added to the xPendingReadyList. Once the
|
||||
scheduler has been resumed it is safe to move all the pending ready
|
||||
tasks from this list into their appropriate ready list. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
--uxSchedulerSuspended;
|
||||
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
portBASE_TYPE xYieldRequired = pdFALSE;
|
||||
|
||||
/* Move any readied tasks from the pending list into the
|
||||
appropriate ready list. */
|
||||
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
|
||||
{
|
||||
vListRemove( &( pxTCB->xEventListItem ) );
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
|
||||
/* If we have moved a task that has a priority higher than
|
||||
the current task then we should yield. */
|
||||
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
||||
{
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If any ticks occurred while the scheduler was suspended then
|
||||
they should be processed now. This ensures the tick count does not
|
||||
slip, and that any delayed tasks are resumed at the correct time. */
|
||||
if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
vTaskIncrementTick();
|
||||
--uxMissedTicks;
|
||||
}
|
||||
|
||||
/* As we have processed some ticks it is appropriate to yield
|
||||
to ensure the highest priority task that is ready to run is
|
||||
the task actually running. */
|
||||
#if configUSE_PREEMPTION == 1
|
||||
{
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
|
||||
{
|
||||
xAlreadyYielded = pdTRUE;
|
||||
xMissedYield = pdFALSE;
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xAlreadyYielded;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* PUBLIC TASK UTILITIES documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
portTickType xTaskGetTickCount( void )
|
||||
{
|
||||
portTickType xTicks;
|
||||
|
||||
/* Critical section required if running on a 16 bit processor. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
xTicks = xTickCount;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xTicks;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
|
||||
{
|
||||
/* A critical section is not required because the variables are of type
|
||||
portBASE_TYPE. */
|
||||
return uxCurrentNumberOfTasks;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
void vTaskList( signed char *pcWriteBuffer )
|
||||
{
|
||||
unsigned portBASE_TYPE uxQueue;
|
||||
|
||||
/* This is a VERY costly function that should be used for debug only.
|
||||
It leaves interrupts disabled for a LONG time. */
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Run through all the lists that could potentially contain a TCB and
|
||||
report the task name, state and stack high water mark. */
|
||||
|
||||
pcWriteBuffer[ 0 ] = ( signed char ) 0x00;
|
||||
strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
|
||||
|
||||
uxQueue = uxTopUsedPriority + 1;
|
||||
|
||||
do
|
||||
{
|
||||
uxQueue--;
|
||||
|
||||
if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
|
||||
}
|
||||
}while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
|
||||
}
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
|
||||
}
|
||||
|
||||
#if( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
|
||||
{
|
||||
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
||||
void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
|
||||
{
|
||||
unsigned portBASE_TYPE uxQueue;
|
||||
unsigned long ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
|
||||
|
||||
/* This is a VERY costly function that should be used for debug only.
|
||||
It leaves interrupts disabled for a LONG time. */
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Run through all the lists that could potentially contain a TCB,
|
||||
generating a table of run timer percentages in the provided
|
||||
buffer. */
|
||||
|
||||
pcWriteBuffer[ 0 ] = ( signed char ) 0x00;
|
||||
strcat( ( char * ) pcWriteBuffer, ( const char * ) "\r\n" );
|
||||
|
||||
uxQueue = uxTopUsedPriority + 1;
|
||||
|
||||
do
|
||||
{
|
||||
uxQueue--;
|
||||
|
||||
if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime );
|
||||
}
|
||||
}while( uxQueue > ( unsigned short ) tskIDLE_PRIORITY );
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime );
|
||||
}
|
||||
|
||||
if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime );
|
||||
}
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
|
||||
{
|
||||
prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
void vTaskStartTrace( signed char * pcBuffer, unsigned long ulBufferSize )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
pcTraceBuffer = ( signed char * )pcBuffer;
|
||||
pcTraceBufferStart = pcBuffer;
|
||||
pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
|
||||
xTracing = pdTRUE;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
unsigned long ulTaskEndTrace( void )
|
||||
{
|
||||
unsigned long ulBufferLength;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
xTracing = pdFALSE;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
ulBufferLength = ( unsigned long ) ( pcTraceBuffer - pcTraceBufferStart );
|
||||
|
||||
return ulBufferLength;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
|
||||
* documented in task.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
void vTaskIncrementTick( void )
|
||||
{
|
||||
/* Called by the portable layer each time a tick interrupt occurs.
|
||||
Increments the tick then checks to see if the new tick value will cause any
|
||||
tasks to be unblocked. */
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
++xTickCount;
|
||||
if( xTickCount == ( portTickType ) 0 )
|
||||
{
|
||||
xList *pxTemp;
|
||||
|
||||
/* Tick count has overflowed so we need to swap the delay lists.
|
||||
If there are any items in pxDelayedTaskList here then there is
|
||||
an error! */
|
||||
pxTemp = pxDelayedTaskList;
|
||||
pxDelayedTaskList = pxOverflowDelayedTaskList;
|
||||
pxOverflowDelayedTaskList = pxTemp;
|
||||
xNumOfOverflows++;
|
||||
}
|
||||
|
||||
/* See if this tick has made a timeout expire. */
|
||||
prvCheckDelayedTasks();
|
||||
}
|
||||
else
|
||||
{
|
||||
++uxMissedTicks;
|
||||
|
||||
/* The tick hook gets called at regular intervals, even if the
|
||||
scheduler is locked. */
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
{
|
||||
extern void vApplicationTickHook( void );
|
||||
|
||||
vApplicationTickHook();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
{
|
||||
extern void vApplicationTickHook( void );
|
||||
|
||||
/* Guard against the tick hook being called when the missed tick
|
||||
count is being unwound (when the scheduler is being unlocked. */
|
||||
if( uxMissedTicks == 0 )
|
||||
{
|
||||
vApplicationTickHook();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
traceTASK_INCREMENT_TICK( xTickCount );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
|
||||
|
||||
void vTaskCleanUpResources( void )
|
||||
{
|
||||
unsigned short usQueue;
|
||||
volatile tskTCB *pxTCB;
|
||||
|
||||
usQueue = ( unsigned short ) uxTopUsedPriority + ( unsigned short ) 1;
|
||||
|
||||
/* Remove any TCB's from the ready queues. */
|
||||
do
|
||||
{
|
||||
usQueue--;
|
||||
|
||||
while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
}while( usQueue > ( unsigned short ) tskIDLE_PRIORITY );
|
||||
|
||||
/* Remove any TCB's from the delayed queue. */
|
||||
while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
|
||||
/* Remove any TCB's from the overflow delayed queue. */
|
||||
while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
|
||||
while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
|
||||
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
|
||||
|
||||
prvDeleteTCB( ( tskTCB * ) pxTCB );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
|
||||
void vTaskSetApplicationTaskTag( xTaskHandle xTask, pdTASK_HOOK_CODE pxTagValue )
|
||||
{
|
||||
tskTCB *xTCB;
|
||||
|
||||
/* If xTask is NULL then we are setting our own task hook. */
|
||||
if( xTask == NULL )
|
||||
{
|
||||
xTCB = ( tskTCB * ) pxCurrentTCB;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTCB = ( tskTCB * ) xTask;
|
||||
}
|
||||
|
||||
/* Save the hook function in the TCB. A critical section is required as
|
||||
the value can be accessed from an interrupt. */
|
||||
portENTER_CRITICAL();
|
||||
xTCB->pxTaskTag = pxTagValue;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
|
||||
pdTASK_HOOK_CODE xTaskGetApplicationTaskTag( xTaskHandle xTask )
|
||||
{
|
||||
tskTCB *xTCB;
|
||||
pdTASK_HOOK_CODE xReturn;
|
||||
|
||||
/* If xTask is NULL then we are setting our own task hook. */
|
||||
if( xTask == NULL )
|
||||
{
|
||||
xTCB = ( tskTCB * ) pxCurrentTCB;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTCB = ( tskTCB * ) xTask;
|
||||
}
|
||||
|
||||
/* Save the hook function in the TCB. A critical section is required as
|
||||
the value can be accessed from an interrupt. */
|
||||
portENTER_CRITICAL();
|
||||
xReturn = xTCB->pxTaskTag;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
|
||||
portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParameter )
|
||||
{
|
||||
tskTCB *xTCB;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* If xTask is NULL then we are calling our own task hook. */
|
||||
if( xTask == NULL )
|
||||
{
|
||||
xTCB = ( tskTCB * ) pxCurrentTCB;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTCB = ( tskTCB * ) xTask;
|
||||
}
|
||||
|
||||
if( xTCB->pxTaskTag != NULL )
|
||||
{
|
||||
xReturn = xTCB->pxTaskTag( pvParameter );
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskSwitchContext( void )
|
||||
{
|
||||
if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
/* The scheduler is currently suspended - do not allow a context
|
||||
switch. */
|
||||
xMissedYield = pdTRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
traceTASK_SWITCHED_OUT();
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
{
|
||||
unsigned long ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE();
|
||||
|
||||
/* Add the amount of time the task has been running to the accumulated
|
||||
time so far. The time the task started running was stored in
|
||||
ulTaskSwitchedInTime. Note that there is no overflow protection here
|
||||
so count values are only valid until the timer overflows. Generally
|
||||
this will be about 1 hour assuming a 1uS timer increment. */
|
||||
pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime );
|
||||
ulTaskSwitchedInTime = ulTempCounter;
|
||||
}
|
||||
#endif
|
||||
|
||||
taskFIRST_CHECK_FOR_STACK_OVERFLOW();
|
||||
taskSECOND_CHECK_FOR_STACK_OVERFLOW();
|
||||
|
||||
/* Find the highest priority queue that contains ready tasks. */
|
||||
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
|
||||
{
|
||||
--uxTopReadyPriority;
|
||||
}
|
||||
|
||||
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
|
||||
same priority get an equal share of the processor time. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
|
||||
|
||||
traceTASK_SWITCHED_IN();
|
||||
vWriteTraceToBuffer();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
|
||||
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
|
||||
SCHEDULER SUSPENDED. */
|
||||
|
||||
/* Place the event list item of the TCB in the appropriate event list.
|
||||
This is placed in the list in priority order so the highest priority task
|
||||
is the first to be woken by the event. */
|
||||
vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
|
||||
|
||||
/* We must remove ourselves from the ready list before adding ourselves
|
||||
to the blocked list as the same list item is used for both lists. We have
|
||||
exclusive access to the ready lists as the scheduler is locked. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
if( xTicksToWait == portMAX_DELAY )
|
||||
{
|
||||
/* Add ourselves to the suspended task list instead of a delayed task
|
||||
list to ensure we are not woken by a timing event. We will block
|
||||
indefinitely. */
|
||||
vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Calculate the time at which the task should be woken if the event does
|
||||
not occur. This may overflow but this doesn't matter. */
|
||||
xTimeToWake = xTickCount + xTicksToWait;
|
||||
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* Calculate the time at which the task should be woken if the event does
|
||||
not occur. This may overflow but this doesn't matter. */
|
||||
xTimeToWake = xTickCount + xTicksToWait;
|
||||
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
|
||||
{
|
||||
tskTCB *pxUnblockedTCB;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
|
||||
SCHEDULER SUSPENDED. It can also be called from within an ISR. */
|
||||
|
||||
/* The event list is sorted in priority order, so we can remove the
|
||||
first in the list, remove the TCB from the delayed list, and add
|
||||
it to the ready list.
|
||||
|
||||
If an event is for a queue that is locked then this function will never
|
||||
get called - the lock count on the queue will get modified instead. This
|
||||
means we can always expect exclusive access to the event list here. */
|
||||
pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
|
||||
vListRemove( &( pxUnblockedTCB->xEventListItem ) );
|
||||
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
|
||||
prvAddTaskToReadyQueue( pxUnblockedTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We cannot access the delayed or ready lists, so will hold this
|
||||
task pending until the scheduler is resumed. */
|
||||
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
|
||||
}
|
||||
|
||||
if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* Return true if the task removed from the event list has
|
||||
a higher priority than the calling task. This allows
|
||||
the calling task to know if it should force a context
|
||||
switch now. */
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut )
|
||||
{
|
||||
pxTimeOut->xOverflowCount = xNumOfOverflows;
|
||||
pxTimeOut->xTimeOnEntering = xTickCount;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
/* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
|
||||
the maximum block time then the task should block indefinitely, and
|
||||
therefore never time out. */
|
||||
if( *pxTicksToWait == portMAX_DELAY )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else /* We are not blocking indefinitely, perform the checks below. */
|
||||
#endif
|
||||
|
||||
if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( ( portTickType ) xTickCount >= ( portTickType ) pxTimeOut->xTimeOnEntering ) )
|
||||
{
|
||||
/* The tick count is greater than the time at which vTaskSetTimeout()
|
||||
was called, but has also overflowed since vTaskSetTimeOut() was called.
|
||||
It must have wrapped all the way around and gone past us again. This
|
||||
passed since vTaskSetTimeout() was called. */
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else if( ( ( portTickType ) ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering ) ) < ( portTickType ) *pxTicksToWait )
|
||||
{
|
||||
/* Not a genuine timeout. Adjust parameters for time remaining. */
|
||||
*pxTicksToWait -= ( ( portTickType ) xTickCount - ( portTickType ) pxTimeOut->xTimeOnEntering );
|
||||
vTaskSetTimeOutState( pxTimeOut );
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vTaskMissedYield( void )
|
||||
{
|
||||
xMissedYield = pdTRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* -----------------------------------------------------------
|
||||
* The Idle task.
|
||||
* ----------------------------------------------------------
|
||||
*
|
||||
* The portTASK_FUNCTION() macro is used to allow port/compiler specific
|
||||
* language extensions. The equivalent prototype for this function is:
|
||||
*
|
||||
* void prvIdleTask( void *pvParameters );
|
||||
*
|
||||
*/
|
||||
static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
||||
{
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* See if any tasks have been deleted. */
|
||||
prvCheckTasksWaitingTermination();
|
||||
|
||||
#if ( configUSE_PREEMPTION == 0 )
|
||||
{
|
||||
/* If we are not using preemption we keep forcing a task switch to
|
||||
see if any other task has become available. If we are using
|
||||
preemption we don't need to do this as any task becoming available
|
||||
will automatically get the processor anyway. */
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
|
||||
{
|
||||
/* When using preemption tasks of equal priority will be
|
||||
timesliced. If a task that is sharing the idle priority is ready
|
||||
to run then the idle task should yield before the end of the
|
||||
timeslice.
|
||||
|
||||
A critical region is not required here as we are just reading from
|
||||
the list, and an occasional incorrect value will not matter. If
|
||||
the ready list at the idle priority contains more than one task
|
||||
then a task other than the idle task is ready to execute. */
|
||||
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( configUSE_IDLE_HOOK == 1 )
|
||||
{
|
||||
extern void vApplicationIdleHook( void );
|
||||
|
||||
/* Call the user defined function from within the idle task. This
|
||||
allows the application designer to add background functionality
|
||||
without the overhead of a separate task.
|
||||
NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
|
||||
CALL A FUNCTION THAT MIGHT BLOCK. */
|
||||
vApplicationIdleHook();
|
||||
}
|
||||
#endif
|
||||
// call nanosleep for smalles sleep time possible
|
||||
// (depending on kernel settings - around 100 microseconds)
|
||||
// decreases idle thread CPU load from 100 to practically 0
|
||||
struct timespec x;
|
||||
x.tv_sec=1;
|
||||
x.tv_nsec=0;
|
||||
nanosleep(&x,NULL);
|
||||
}
|
||||
} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* File private functions documented at the top of the file.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth )
|
||||
{
|
||||
/* Store the function name in the TCB. */
|
||||
#if configMAX_TASK_NAME_LEN > 1
|
||||
{
|
||||
/* Don't bring strncpy into the build unnecessarily. */
|
||||
strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN );
|
||||
}
|
||||
#endif
|
||||
pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = '\0';
|
||||
|
||||
/* This is used as an array index so must ensure it's not too large. First
|
||||
remove the privilege bit if one is present. */
|
||||
if( uxPriority >= configMAX_PRIORITIES )
|
||||
{
|
||||
uxPriority = configMAX_PRIORITIES - 1;
|
||||
}
|
||||
|
||||
pxTCB->uxPriority = uxPriority;
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
{
|
||||
pxTCB->uxBasePriority = uxPriority;
|
||||
}
|
||||
#endif
|
||||
|
||||
vListInitialiseItem( &( pxTCB->xGenericListItem ) );
|
||||
vListInitialiseItem( &( pxTCB->xEventListItem ) );
|
||||
|
||||
/* Set the pxTCB as a link back from the xListItem. This is so we can get
|
||||
back to the containing TCB from a generic item in a list. */
|
||||
listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
|
||||
|
||||
/* Event lists are always in priority order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
|
||||
listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
{
|
||||
pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
||||
{
|
||||
pxTCB->pxTaskTag = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
{
|
||||
pxTCB->ulRunTimeCounter = 0UL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
{
|
||||
vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
|
||||
}
|
||||
#else
|
||||
{
|
||||
( void ) xRegions;
|
||||
( void ) usStackDepth;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( portUSING_MPU_WRAPPERS == 1 )
|
||||
|
||||
void vTaskAllocateMPURegions( xTaskHandle xTaskToModify, const xMemoryRegion * const xRegions )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
if( xTaskToModify == pxCurrentTCB )
|
||||
{
|
||||
xTaskToModify = NULL;
|
||||
}
|
||||
|
||||
/* If null is passed in here then we are deleting ourselves. */
|
||||
pxTCB = prvGetTCBFromHandle( xTaskToModify );
|
||||
|
||||
vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
#endif
|
||||
|
||||
static void prvInitialiseTaskLists( void )
|
||||
{
|
||||
unsigned portBASE_TYPE uxPriority;
|
||||
|
||||
for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
|
||||
{
|
||||
vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
|
||||
}
|
||||
|
||||
vListInitialise( ( xList * ) &xDelayedTaskList1 );
|
||||
vListInitialise( ( xList * ) &xDelayedTaskList2 );
|
||||
vListInitialise( ( xList * ) &xPendingReadyList );
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
vListInitialise( ( xList * ) &xTasksWaitingTermination );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||
{
|
||||
vListInitialise( ( xList * ) &xSuspendedTaskList );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
|
||||
using list2. */
|
||||
pxDelayedTaskList = &xDelayedTaskList1;
|
||||
pxOverflowDelayedTaskList = &xDelayedTaskList2;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckTasksWaitingTermination( void )
|
||||
{
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
portBASE_TYPE xListIsEmpty;
|
||||
|
||||
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
|
||||
too often in the idle task. */
|
||||
if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
|
||||
xTaskResumeAll();
|
||||
|
||||
if( !xListIsEmpty )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
--uxCurrentNumberOfTasks;
|
||||
--uxTasksDeleted;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
prvDeleteTCB( pxTCB );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer )
|
||||
{
|
||||
tskTCB *pxNewTCB;
|
||||
|
||||
/* Allocate space for the TCB. Where the memory comes from depends on
|
||||
the implementation of the port malloc function. */
|
||||
pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
|
||||
|
||||
if( pxNewTCB != NULL )
|
||||
{
|
||||
/* Allocate space for the stack used by the task being created.
|
||||
The base of the stack memory stored in the TCB so the task can
|
||||
be deleted later if required. */
|
||||
pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer );
|
||||
|
||||
if( pxNewTCB->pxStack == NULL )
|
||||
{
|
||||
/* Could not allocate the stack. Delete the allocated TCB. */
|
||||
vPortFree( pxNewTCB );
|
||||
pxNewTCB = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just to help debugging. */
|
||||
memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
|
||||
}
|
||||
}
|
||||
|
||||
return pxNewTCB;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
static void prvListTaskWithinSingleList( const signed char *pcWriteBuffer, xList *pxList, signed char cStatus )
|
||||
{
|
||||
volatile tskTCB *pxNextTCB, *pxFirstTCB;
|
||||
unsigned short usStackRemaining;
|
||||
|
||||
/* Write the details of all the TCB's in pxList into the buffer. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
|
||||
do
|
||||
{
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
|
||||
#if ( portSTACK_GROWTH > 0 )
|
||||
{
|
||||
usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxEndOfStack );
|
||||
}
|
||||
#else
|
||||
{
|
||||
usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned char * ) pxNextTCB->pxStack );
|
||||
}
|
||||
#endif
|
||||
|
||||
sprintf( pcStatusString, ( char * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
|
||||
strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatusString );
|
||||
|
||||
} while( pxNextTCB != pxFirstTCB );
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
||||
static void prvGenerateRunTimeStatsForTasksInList( const signed char *pcWriteBuffer, xList *pxList, unsigned long ulTotalRunTime )
|
||||
{
|
||||
volatile tskTCB *pxNextTCB, *pxFirstTCB;
|
||||
unsigned long ulStatsAsPercentage;
|
||||
|
||||
/* Write the run time stats of all the TCB's in pxList into the buffer. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
|
||||
do
|
||||
{
|
||||
/* Get next TCB in from the list. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
|
||||
|
||||
/* Divide by zero check. */
|
||||
if( ulTotalRunTime > 0UL )
|
||||
{
|
||||
/* Has the task run at all? */
|
||||
if( pxNextTCB->ulRunTimeCounter == 0 )
|
||||
{
|
||||
/* The task has used no CPU time at all. */
|
||||
sprintf( pcStatsString, ( char * ) "%s\t\t0\t\t0%%\r\n", pxNextTCB->pcTaskName );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* What percentage of the total run time as the task used?
|
||||
This will always be rounded down to the nearest integer. */
|
||||
ulStatsAsPercentage = ( 100UL * pxNextTCB->ulRunTimeCounter ) / ulTotalRunTime;
|
||||
|
||||
if( ulStatsAsPercentage > 0UL )
|
||||
{
|
||||
sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t%u%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter, ( unsigned int ) ulStatsAsPercentage );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the percentage is zero here then the task has
|
||||
consumed less than 1% of the total run time. */
|
||||
sprintf( pcStatsString, ( char * ) "%s\t\t%u\t\t<1%%\r\n", pxNextTCB->pcTaskName, ( unsigned int ) pxNextTCB->ulRunTimeCounter );
|
||||
}
|
||||
}
|
||||
|
||||
strcat( ( char * ) pcWriteBuffer, ( char * ) pcStatsString );
|
||||
}
|
||||
|
||||
} while( pxNextTCB != pxFirstTCB );
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
||||
|
||||
static unsigned short usTaskCheckFreeStackSpace( const unsigned char * pucStackByte )
|
||||
{
|
||||
register unsigned short usCount = 0;
|
||||
|
||||
while( *pucStackByte == tskSTACK_FILL_BYTE )
|
||||
{
|
||||
pucStackByte -= portSTACK_GROWTH;
|
||||
usCount++;
|
||||
}
|
||||
|
||||
usCount /= sizeof( portSTACK_TYPE );
|
||||
|
||||
return usCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
|
||||
|
||||
unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask )
|
||||
{
|
||||
tskTCB *pxTCB;
|
||||
unsigned char *pcEndOfStack;
|
||||
unsigned portBASE_TYPE uxReturn;
|
||||
|
||||
pxTCB = prvGetTCBFromHandle( xTask );
|
||||
|
||||
#if portSTACK_GROWTH < 0
|
||||
{
|
||||
pcEndOfStack = ( unsigned char * ) pxTCB->pxStack;
|
||||
}
|
||||
#else
|
||||
{
|
||||
pcEndOfStack = ( unsigned char * ) pxTCB->pxEndOfStack;
|
||||
}
|
||||
#endif
|
||||
|
||||
uxReturn = ( unsigned portBASE_TYPE ) usTaskCheckFreeStackSpace( pcEndOfStack );
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
|
||||
|
||||
static void prvDeleteTCB( tskTCB *pxTCB )
|
||||
{
|
||||
/* Free up the memory allocated by the scheduler for the task. It is up to
|
||||
the task to free any memory allocated at the application level. */
|
||||
vPortFreeAligned( pxTCB->pxStack );
|
||||
vPortFree( pxTCB );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
|
||||
|
||||
xTaskHandle xTaskGetCurrentTaskHandle( void )
|
||||
{
|
||||
xTaskHandle xReturn;
|
||||
|
||||
/* A critical section is not required as this is not called from
|
||||
an interrupt and the current TCB will always be the same for any
|
||||
individual execution thread. */
|
||||
xReturn = pxCurrentTCB;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_xTaskGetSchedulerState == 1 )
|
||||
|
||||
portBASE_TYPE xTaskGetSchedulerState( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
if( xSchedulerRunning == pdFALSE )
|
||||
{
|
||||
xReturn = taskSCHEDULER_NOT_STARTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
|
||||
{
|
||||
xReturn = taskSCHEDULER_RUNNING;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = taskSCHEDULER_SUSPENDED;
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
|
||||
void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder )
|
||||
{
|
||||
tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
|
||||
|
||||
if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
|
||||
{
|
||||
/* Adjust the mutex holder state to account for its new priority. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority );
|
||||
|
||||
/* If the task being modified is in the ready state it will need to
|
||||
be moved in to a new list. */
|
||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) )
|
||||
{
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Inherit the priority before being moved into the new list. */
|
||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just inherit the priority. */
|
||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
|
||||
void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder )
|
||||
{
|
||||
tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder;
|
||||
|
||||
if( pxMutexHolder != NULL )
|
||||
{
|
||||
if( pxTCB->uxPriority != pxTCB->uxBasePriority )
|
||||
{
|
||||
/* We must be the running task to be able to give the mutex back.
|
||||
Remove ourselves from the ready list we currently appear in. */
|
||||
vListRemove( &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Disinherit the priority before adding ourselves into the new
|
||||
ready list. */
|
||||
pxTCB->uxPriority = pxTCB->uxBasePriority;
|
||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority );
|
||||
prvAddTaskToReadyQueue( pxTCB );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
||||
void vTaskEnterCritical( void )
|
||||
{
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
pxCurrentTCB->uxCriticalNesting++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||
|
||||
void vTaskExitCritical( void )
|
||||
{
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
if( pxCurrentTCB->uxCriticalNesting > 0 )
|
||||
{
|
||||
pxCurrentTCB->uxCriticalNesting--;
|
||||
|
||||
if( pxCurrentTCB->uxCriticalNesting == 0 )
|
||||
{
|
||||
portENABLE_INTERRUPTS();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,42 +1,42 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_USB_UTIL USB utility functions
|
||||
* @brief USB utility functions
|
||||
* @{
|
||||
*
|
||||
* @file pios_usb_util.c
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief USB utility functions
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "pios_usb_util.h"
|
||||
|
||||
uint8_t * PIOS_USB_UTIL_AsciiToUtf8(uint8_t * dst, uint8_t * src, uint16_t srclen)
|
||||
{
|
||||
for (uint8_t i = 0; i < srclen; i++) {
|
||||
*dst = *src;
|
||||
dst += 2;
|
||||
src += 1;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_USB_UTIL USB utility functions
|
||||
* @brief USB utility functions
|
||||
* @{
|
||||
*
|
||||
* @file pios_usb_util.c
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief USB utility functions
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "pios_usb_util.h"
|
||||
|
||||
uint8_t * PIOS_USB_UTIL_AsciiToUtf8(uint8_t * dst, uint8_t * src, uint16_t srclen)
|
||||
{
|
||||
for (uint8_t i = 0; i < srclen; i++) {
|
||||
*dst = *src;
|
||||
dst += 2;
|
||||
src += 1;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
@ -1,142 +1,142 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_IAP IAP Functions
|
||||
* @brief STM32F4xx Hardware dependent I2C functionality
|
||||
* @{
|
||||
*
|
||||
* @file pios_iap.c
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief In application programming functions
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/****************************************************************************************
|
||||
* Header files
|
||||
****************************************************************************************/
|
||||
#include <pios.h>
|
||||
|
||||
/****************************************************************************************
|
||||
* Private Definitions/Macros
|
||||
****************************************************************************************/
|
||||
|
||||
/* these definitions reside here for protection and privacy. */
|
||||
#define IAP_MAGIC_WORD_1 0x1122
|
||||
#define IAP_MAGIC_WORD_2 0xAA55
|
||||
|
||||
#define UPPERWORD16(lw) (uint16_t)((uint32_t)(lw)>>16)
|
||||
#define LOWERWORD16(lw) (uint16_t)((uint32_t)(lw)&0x0000ffff)
|
||||
#define UPPERBYTE(w) (uint8_t)((w)>>8)
|
||||
#define LOWERBYTE(w) (uint8_t)((w)&0x00ff)
|
||||
|
||||
/****************************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* Private (static) Data
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* Public/Global Data
|
||||
****************************************************************************************/
|
||||
|
||||
/*!
|
||||
* \brief PIOS_IAP_Init - performs required initializations for iap module.
|
||||
* \param none.
|
||||
* \return none.
|
||||
* \retval none.
|
||||
*
|
||||
* Created: Sep 8, 2010 10:10:48 PM by joe
|
||||
*/
|
||||
void PIOS_IAP_Init( void )
|
||||
{
|
||||
/* Enable CRC clock */
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
|
||||
|
||||
/* Enable PWR and BKP clock */
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_AHB1Periph_BKPSRAM, ENABLE);
|
||||
|
||||
/* Enable write access to Backup domain */
|
||||
PWR_BackupAccessCmd(ENABLE);
|
||||
|
||||
/* Clear Tamper pin Event(TE) pending flag */
|
||||
RTC_ClearFlag(RTC_FLAG_TAMP1F);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Determines if an In-Application-Programming request has been made.
|
||||
* \param *comm - Which communication stream to use for the IAP (USB, Telemetry, I2C, SPI, etc)
|
||||
* \return TRUE - if correct sequence found, along with 'comm' updated.
|
||||
* FALSE - Note that 'comm' will have an invalid comm identifier.
|
||||
* \retval
|
||||
*
|
||||
*/
|
||||
uint32_t PIOS_IAP_CheckRequest( void )
|
||||
{
|
||||
uint32_t retval = false;
|
||||
uint16_t reg1;
|
||||
uint16_t reg2;
|
||||
|
||||
reg1 = RTC_ReadBackupRegister( MAGIC_REG_1 );
|
||||
reg2 = RTC_ReadBackupRegister( MAGIC_REG_2 );
|
||||
|
||||
if( reg1 == IAP_MAGIC_WORD_1 && reg2 == IAP_MAGIC_WORD_2 ) {
|
||||
// We have a match.
|
||||
retval = true;
|
||||
} else {
|
||||
retval = false;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Sets the 1st word of the request sequence.
|
||||
* \param n/a
|
||||
* \return n/a
|
||||
* \retval
|
||||
*/
|
||||
void PIOS_IAP_SetRequest1(void)
|
||||
{
|
||||
RTC_WriteBackupRegister( MAGIC_REG_1, IAP_MAGIC_WORD_1);
|
||||
}
|
||||
|
||||
void PIOS_IAP_SetRequest2(void)
|
||||
{
|
||||
RTC_WriteBackupRegister( MAGIC_REG_2, IAP_MAGIC_WORD_2);
|
||||
}
|
||||
|
||||
void PIOS_IAP_ClearRequest(void)
|
||||
{
|
||||
RTC_WriteBackupRegister( MAGIC_REG_1, 0);
|
||||
RTC_WriteBackupRegister( MAGIC_REG_2, 0);
|
||||
}
|
||||
|
||||
uint16_t PIOS_IAP_ReadBootCount(void)
|
||||
{
|
||||
return RTC_ReadBackupRegister ( IAP_BOOTCOUNT );
|
||||
}
|
||||
|
||||
void PIOS_IAP_WriteBootCount (uint16_t boot_count)
|
||||
{
|
||||
RTC_WriteBackupRegister ( IAP_BOOTCOUNT, boot_count );
|
||||
}
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_IAP IAP Functions
|
||||
* @brief STM32F4xx Hardware dependent I2C functionality
|
||||
* @{
|
||||
*
|
||||
* @file pios_iap.c
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief In application programming functions
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/****************************************************************************************
|
||||
* Header files
|
||||
****************************************************************************************/
|
||||
#include <pios.h>
|
||||
|
||||
/****************************************************************************************
|
||||
* Private Definitions/Macros
|
||||
****************************************************************************************/
|
||||
|
||||
/* these definitions reside here for protection and privacy. */
|
||||
#define IAP_MAGIC_WORD_1 0x1122
|
||||
#define IAP_MAGIC_WORD_2 0xAA55
|
||||
|
||||
#define UPPERWORD16(lw) (uint16_t)((uint32_t)(lw)>>16)
|
||||
#define LOWERWORD16(lw) (uint16_t)((uint32_t)(lw)&0x0000ffff)
|
||||
#define UPPERBYTE(w) (uint8_t)((w)>>8)
|
||||
#define LOWERBYTE(w) (uint8_t)((w)&0x00ff)
|
||||
|
||||
/****************************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* Private (static) Data
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* Public/Global Data
|
||||
****************************************************************************************/
|
||||
|
||||
/*!
|
||||
* \brief PIOS_IAP_Init - performs required initializations for iap module.
|
||||
* \param none.
|
||||
* \return none.
|
||||
* \retval none.
|
||||
*
|
||||
* Created: Sep 8, 2010 10:10:48 PM by joe
|
||||
*/
|
||||
void PIOS_IAP_Init( void )
|
||||
{
|
||||
/* Enable CRC clock */
|
||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
|
||||
|
||||
/* Enable PWR and BKP clock */
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_AHB1Periph_BKPSRAM, ENABLE);
|
||||
|
||||
/* Enable write access to Backup domain */
|
||||
PWR_BackupAccessCmd(ENABLE);
|
||||
|
||||
/* Clear Tamper pin Event(TE) pending flag */
|
||||
RTC_ClearFlag(RTC_FLAG_TAMP1F);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Determines if an In-Application-Programming request has been made.
|
||||
* \param *comm - Which communication stream to use for the IAP (USB, Telemetry, I2C, SPI, etc)
|
||||
* \return TRUE - if correct sequence found, along with 'comm' updated.
|
||||
* FALSE - Note that 'comm' will have an invalid comm identifier.
|
||||
* \retval
|
||||
*
|
||||
*/
|
||||
uint32_t PIOS_IAP_CheckRequest( void )
|
||||
{
|
||||
uint32_t retval = false;
|
||||
uint16_t reg1;
|
||||
uint16_t reg2;
|
||||
|
||||
reg1 = RTC_ReadBackupRegister( MAGIC_REG_1 );
|
||||
reg2 = RTC_ReadBackupRegister( MAGIC_REG_2 );
|
||||
|
||||
if( reg1 == IAP_MAGIC_WORD_1 && reg2 == IAP_MAGIC_WORD_2 ) {
|
||||
// We have a match.
|
||||
retval = true;
|
||||
} else {
|
||||
retval = false;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Sets the 1st word of the request sequence.
|
||||
* \param n/a
|
||||
* \return n/a
|
||||
* \retval
|
||||
*/
|
||||
void PIOS_IAP_SetRequest1(void)
|
||||
{
|
||||
RTC_WriteBackupRegister( MAGIC_REG_1, IAP_MAGIC_WORD_1);
|
||||
}
|
||||
|
||||
void PIOS_IAP_SetRequest2(void)
|
||||
{
|
||||
RTC_WriteBackupRegister( MAGIC_REG_2, IAP_MAGIC_WORD_2);
|
||||
}
|
||||
|
||||
void PIOS_IAP_ClearRequest(void)
|
||||
{
|
||||
RTC_WriteBackupRegister( MAGIC_REG_1, 0);
|
||||
RTC_WriteBackupRegister( MAGIC_REG_2, 0);
|
||||
}
|
||||
|
||||
uint16_t PIOS_IAP_ReadBootCount(void)
|
||||
{
|
||||
return RTC_ReadBackupRegister ( IAP_BOOTCOUNT );
|
||||
}
|
||||
|
||||
void PIOS_IAP_WriteBootCount (uint16_t boot_count)
|
||||
{
|
||||
RTC_WriteBackupRegister ( IAP_BOOTCOUNT, boot_count );
|
||||
}
|
||||
|
@ -1,656 +1,656 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_RFM22B Radio Functions
|
||||
* @brief PIOS interface for RFM22B Radio
|
||||
* @{
|
||||
*
|
||||
* @file pios_rfm22b_priv.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief RFM22B private definitions.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_RFM22B_PRIV_H
|
||||
#define PIOS_RFM22B_PRIV_H
|
||||
|
||||
#include <pios.h>
|
||||
#include "fifo_buffer.h"
|
||||
#include "pios_rfm22b.h"
|
||||
|
||||
extern const struct pios_com_driver pios_rfm22b_com_driver;
|
||||
|
||||
// ************************************
|
||||
|
||||
#define RFM22_DEVICE_VERSION_V2 0x02
|
||||
#define RFM22_DEVICE_VERSION_A0 0x04
|
||||
#define RFM22_DEVICE_VERSION_B1 0x06
|
||||
|
||||
// ************************************
|
||||
|
||||
#define RFM22_MIN_CARRIER_FREQUENCY_HZ 240000000ul
|
||||
#define RFM22_MAX_CARRIER_FREQUENCY_HZ 930000000ul
|
||||
|
||||
// ************************************
|
||||
|
||||
enum { RX_SCAN_SPECTRUM = 0,
|
||||
RX_WAIT_PREAMBLE_MODE,
|
||||
RX_WAIT_SYNC_MODE,
|
||||
RX_DATA_MODE,
|
||||
TX_DATA_MODE,
|
||||
TX_STREAM_MODE,
|
||||
TX_CARRIER_MODE,
|
||||
TX_PN_MODE};
|
||||
|
||||
// ************************************
|
||||
|
||||
#define BIT0 (1u << 0)
|
||||
#define BIT1 (1u << 1)
|
||||
#define BIT2 (1u << 2)
|
||||
#define BIT3 (1u << 3)
|
||||
#define BIT4 (1u << 4)
|
||||
#define BIT5 (1u << 5)
|
||||
#define BIT6 (1u << 6)
|
||||
#define BIT7 (1u << 7)
|
||||
|
||||
// ************************************
|
||||
|
||||
#define RFM22_DEVICE_TYPE 0x00 // R
|
||||
#define RFM22_DT_MASK 0x1F
|
||||
|
||||
#define RFM22_DEVICE_VERSION 0x01 // R
|
||||
#define RFM22_DV_MASK 0x1F
|
||||
|
||||
#define RFM22_device_status 0x02 // R
|
||||
#define RFM22_ds_cps_mask 0x03 // Chip Power State mask
|
||||
#define RFM22_ds_cps_idle 0x00 // IDLE Chip Power State
|
||||
#define RFM22_ds_cps_rx 0x01 // RX Chip Power State
|
||||
#define RFM22_ds_cps_tx 0x02 // TX Chip Power State
|
||||
//#define RFM22_ds_lockdet 0x04 //
|
||||
//#define RFM22_ds_freqerr 0x08 //
|
||||
#define RFM22_ds_headerr 0x10 // Header Error Status. Indicates if the received packet has a header check error
|
||||
#define RFM22_ds_rxffem 0x20 // RX FIFO Empty Status
|
||||
#define RFM22_ds_ffunfl 0x40 // RX/TX FIFO Underflow Status
|
||||
#define RFM22_ds_ffovfl 0x80 // RX/TX FIFO Overflow Status
|
||||
|
||||
#define RFM22_interrupt_status1 0x03 // R
|
||||
#define RFM22_is1_icrerror BIT0 // CRC Error. When set to 1 the cyclic redundancy check is failed.
|
||||
#define RFM22_is1_ipkvalid BIT1 // Valid Packet Received.When set to 1 a valid packet has been received.
|
||||
#define RFM22_is1_ipksent BIT2 // Packet Sent Interrupt. When set to1 a valid packet has been transmitted.
|
||||
#define RFM22_is1_iext BIT3 // External Interrupt. When set to 1 an interrupt occurred on one of the GPIO’s if it is programmed so. The status can be checked in register 0Eh. See GPIOx Configuration section for the details.
|
||||
#define RFM22_is1_irxffafull BIT4 // RX FIFO Almost Full.When set to 1 the RX FIFO has met its almost full threshold and needs to be read by the microcontroller.
|
||||
#define RFM22_is1_ixtffaem BIT5 // TX FIFO Almost Empty. When set to 1 the TX FIFO is almost empty and needs to be filled.
|
||||
#define RFM22_is1_itxffafull BIT6 // TX FIFO Almost Full. When set to 1 the TX FIFO has met its almost full threshold and needs to be transmitted.
|
||||
#define RFM22_is1_ifferr BIT7 // FIFO Underflow/Overflow Error. When set to 1 the TX or RX FIFO has overflowed or underflowed.
|
||||
|
||||
#define RFM22_interrupt_status2 0x04 // R
|
||||
#define RFM22_is2_ipor BIT0 // Power-on-Reset (POR). When the chip detects a Power on Reset above the desired setting this bit will be set to 1.
|
||||
#define RFM22_is2_ichiprdy BIT1 // Chip Ready (XTAL). When a chip ready event has been detected this bit will be set to 1.
|
||||
#define RFM22_is2_ilbd BIT2 // Low Battery Detect. When a low battery event is been detected this bit will be set to 1. This interrupt event is saved even if it is not enabled by the mask register bit and causes an interrupt after it is enabled.
|
||||
#define RFM22_is2_iwut BIT3 // Wake-Up-Timer. On the expiration of programmed wake-up timer this bit will be set to 1.
|
||||
#define RFM22_is2_irssi BIT4 // RSSI. When RSSI level exceeds the programmed threshold this bit will be set to 1.
|
||||
#define RFM22_is2_ipreainval BIT5 // Invalid Preamble Detected. When the preamble is not found within a period of time set by the invalid preamble detection threshold in Register 54h, this bit will be set to 1.
|
||||
#define RFM22_is2_ipreaval BIT6 // Valid Preamble Detected. When a preamble is detected this bit will be set to 1.
|
||||
#define RFM22_is2_iswdet BIT7 // Sync Word Detected. When a sync word is detected this bit will be set to 1.
|
||||
|
||||
#define RFM22_interrupt_enable1 0x05 // R/W
|
||||
#define RFM22_ie1_encrcerror BIT0 // Enable CRC Error. When set to 1 the CRC Error interrupt will be enabled.
|
||||
#define RFM22_ie1_enpkvalid BIT1 // Enable Valid Packet Received. When ipkvalid = 1 the Valid Packet Received Interrupt will be enabled.
|
||||
#define RFM22_ie1_enpksent BIT2 // Enable Packet Sent. When ipksent =1 the Packet Sense Interrupt will be enabled.
|
||||
#define RFM22_ie1_enext BIT3 // Enable External Interrupt. When set to 1 the External Interrupt will be enabled.
|
||||
#define RFM22_ie1_enrxffafull BIT4 // Enable RX FIFO Almost Full. When set to 1 the RX FIFO Almost Full interrupt will be enabled.
|
||||
#define RFM22_ie1_entxffaem BIT5 // Enable TX FIFO Almost Empty. When set to 1 the TX FIFO Almost Empty interrupt will be enabled.
|
||||
#define RFM22_ie1_entxffafull BIT6 // Enable TX FIFO Almost Full. When set to 1 the TX FIFO Almost Full interrupt will be enabled.
|
||||
#define RFM22_ie1_enfferr BIT7 // Enable FIFO Underflow/Overflow. When set to 1 the FIFO Underflow/Overflow interrupt will be enabled.
|
||||
|
||||
#define RFM22_interrupt_enable2 0x06 // R/W
|
||||
#define RFM22_ie2_enpor BIT0 // Enable POR. When set to 1 the POR interrupt will be enabled.
|
||||
#define RFM22_ie2_enchiprdy BIT1 // Enable Chip Ready (XTAL). When set to 1 the Chip Ready interrupt will be enabled.
|
||||
#define RFM22_ie2_enlbd BIT2 // Enable Low Battery Detect. When set to 1 the Low Battery Detect interrupt will be enabled.
|
||||
#define RFM22_ie2_enwut BIT3 // Enable Wake-Up Timer. When set to 1 the Wake-Up Timer interrupt will be enabled.
|
||||
#define RFM22_ie2_enrssi BIT4 // Enable RSSI. When set to 1 the RSSI Interrupt will be enabled.
|
||||
#define RFM22_ie2_enpreainval BIT5 // Enable Invalid Preamble Detected. When mpreadet =1 the Invalid Preamble Detected Interrupt will be enabled.
|
||||
#define RFM22_ie2_enpreaval BIT6 // Enable Valid Preamble Detected. When mpreadet =1 the Valid Preamble Detected Interrupt will be enabled.
|
||||
#define RFM22_ie2_enswdet BIT7 // Enable Sync Word Detected. When mpreadet =1 the Preamble Detected Interrupt will be enabled.
|
||||
|
||||
#define RFM22_op_and_func_ctrl1 0x07 // R/W
|
||||
#define RFM22_opfc1_xton 0x01 // READY Mode (Xtal is ON).
|
||||
#define RFM22_opfc1_pllon 0x02 // TUNE Mode (PLL is ON). When pllon = 1 the PLL will remain enabled in Idle State. This will for faster turn-around time at the cost of increased current consumption in Idle State.
|
||||
#define RFM22_opfc1_rxon 0x04 // RX on in Manual Receiver Mode. Automatically cleared if Multiple Packets config. is disabled and a valid packet received.
|
||||
#define RFM22_opfc1_txon 0x08 // TX on in Manual Transmit Mode. Automatically cleared in FIFO mode once the packet is sent. Transmission can be aborted during packet transmission, however, when no data has been sent yet, transmission can only be aborted after the device is programmed to “unmodulated carrier” ("Register 71h. Modulation Mode Control 2").
|
||||
#define RFM22_opfc1_x32ksel 0x10 // 32,768 kHz Crystal Oscillator Select. 0: RC oscillator 1: 32 kHz crystal
|
||||
#define RFM22_opfc1_enwt 0x20 // Enable Wake-Up-Timer. Enabled when enwt = 1. If the Wake-up-Timer function is enabled it will operate in any mode and notify the microcontroller through the GPIO interrupt when the timer expires.
|
||||
#define RFM22_opfc1_enlbd 0x40 // Enable Low Battery Detect. When this bit is set to 1 the Low Battery Detector circuit and threshold comparison will be enabled.
|
||||
#define RFM22_opfc1_swres 0x80 // Software Register Reset Bit. This bit may be used to reset all registers simultaneously to a DEFAULT state, without the need for sequentially writing to each individual register. The RESET is accomplished by setting swres = 1. This bit will be automatically cleared.
|
||||
|
||||
#define RFM22_op_and_func_ctrl2 0x08 // R/W
|
||||
#define RFM22_opfc2_ffclrtx 0x01 // TX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrtx =1 followed by ffclrtx = 0 will clear the contents of the TX FIFO.
|
||||
#define RFM22_opfc2_ffclrrx 0x02 // RX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrrx =1 followed by ffclrrx = 0 will clear the contents of the RX FIFO.
|
||||
#define RFM22_opfc2_enldm 0x04 // Enable Low Duty Cycle Mode. If this bit is set to 1 then the chip turns on the RX regularly. The frequency should be set in the Wake-Up Timer Period register, while the minimum ON time should be set in the Low-Duty Cycle Mode Duration register. The FIFO mode should be enabled also.
|
||||
#define RFM22_opfc2_autotx 0x08 // Automatic Transmission. When autotx = 1 the transceiver will enter automatically TX State when the FIFO is almost full. When the FIFO is empty it will automatically return to the Idle State.
|
||||
#define RFM22_opfc2_rxmpk 0x10 // RX Multi Packet. When the chip is selected to use FIFO Mode (dtmod[1:0]) and RX Packet Handling (enpacrx) then it will fill up the FIFO with multiple valid packets if this bit is set, otherwise the transceiver will automatically leave the RX State after the first valid packet has been received.
|
||||
#define RFM22_opfc2_antdiv_mask 0xE0 // Enable Antenna Diversity. The GPIO must be configured for Antenna Diversity for the algorithm to work properly.
|
||||
|
||||
#define RFM22_xtal_osc_load_cap 0x09 // R/W
|
||||
#define RFM22_xolc_xlc_mask 0x7F // Tuning Capacitance for the 30 MHz XTAL.
|
||||
#define RFM22_xolc_xtalshft 0x80 // Additional capacitance to course shift the frequency if xlc[6:0] is not sufficient. Not binary with xlc[6:0].
|
||||
|
||||
#define RFM22_cpu_output_clk 0x0A // R/W
|
||||
#define RFM22_coc_30MHz 0x00
|
||||
#define RFM22_coc_15MHz 0x01
|
||||
#define RFM22_coc_10MHz 0x02
|
||||
#define RFM22_coc_4MHz 0x03
|
||||
#define RFM22_coc_3MHz 0x04
|
||||
#define RFM22_coc_2MHz 0x05
|
||||
#define RFM22_coc_1MHz 0x06
|
||||
#define RFM22_coc_32768Hz 0x07
|
||||
#define RFM22_coc_enlfc 0x08
|
||||
#define RFM22_coc_0cycle 0x00
|
||||
#define RFM22_coc_128cycles 0x10
|
||||
#define RFM22_coc_256cycles 0x20
|
||||
#define RFM22_coc_512cycles 0x30
|
||||
|
||||
#define RFM22_gpio0_config 0x0B // R/W
|
||||
#define RFM22_gpio0_config_por 0x00 // Power-On-Reset (output)
|
||||
#define RFM22_gpio0_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
|
||||
#define RFM22_gpio0_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
|
||||
#define RFM22_gpio0_config_ddi 0x03 // Direct Digital Input
|
||||
#define RFM22_gpio0_config_eife 0x04 // External Interrupt, falling edge (input)
|
||||
#define RFM22_gpio0_config_eire 0x05 // External Interrupt, rising edge (input)
|
||||
#define RFM22_gpio0_config_eisc 0x06 // External Interrupt, state change (input)
|
||||
#define RFM22_gpio0_config_ai 0x07 // ADC Analog Input
|
||||
#define RFM22_gpio0_config_atni 0x08 // Reserved (Analog Test N Input)
|
||||
#define RFM22_gpio0_config_atpi 0x09 // Reserved (Analog Test P Input)
|
||||
#define RFM22_gpio0_config_ddo 0x0A // Direct Digital Output
|
||||
#define RFM22_gpio0_config_dto 0x0B // Reserved (Digital Test Output)
|
||||
#define RFM22_gpio0_config_atno 0x0C // Reserved (Analog Test N Output)
|
||||
#define RFM22_gpio0_config_atpo 0x0D // Reserved (Analog Test P Output)
|
||||
#define RFM22_gpio0_config_rv 0xOE // Reference Voltage (output)
|
||||
#define RFM22_gpio0_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
|
||||
#define RFM22_gpio0_config_txd 0x10 // TX Data input for direct modulation (input)
|
||||
#define RFM22_gpio0_config_err 0x11 // External Retransmission Request (input)
|
||||
#define RFM22_gpio0_config_txstate 0x12 // TX State (output)
|
||||
#define RFM22_gpio0_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
|
||||
#define RFM22_gpio0_config_rxd 0x14 // RX Data (output)
|
||||
#define RFM22_gpio0_config_rxstate 0x15 // RX State (output)
|
||||
#define RFM22_gpio0_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
|
||||
#define RFM22_gpio0_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio0_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio0_config_vpd 0x19 // Valid Preamble Detected (output)
|
||||
#define RFM22_gpio0_config_ipd 0x1A // Invalid Preamble Detected (output)
|
||||
#define RFM22_gpio0_config_swd 0x1B // Sync Word Detected (output)
|
||||
#define RFM22_gpio0_config_cca 0x1C // Clear Channel Assessment (output)
|
||||
#define RFM22_gpio0_config_vdd 0x1D // VDD
|
||||
#define RFM22_gpio0_config_pup 0x20
|
||||
#define RFM22_gpio0_config_drv0 0x00 // output drive level
|
||||
#define RFM22_gpio0_config_drv1 0x40 // output drive level
|
||||
#define RFM22_gpio0_config_drv2 0x80 // output drive level
|
||||
#define RFM22_gpio0_config_drv3 0xC0 // output drive level
|
||||
|
||||
#define RFM22_gpio1_config 0x0C // R/W
|
||||
#define RFM22_gpio1_config_ipor 0x00 // Inverted Power-On-Reset (output)
|
||||
#define RFM22_gpio1_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
|
||||
#define RFM22_gpio1_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
|
||||
#define RFM22_gpio1_config_ddi 0x03 // Direct Digital Input
|
||||
#define RFM22_gpio1_config_eife 0x04 // External Interrupt, falling edge (input)
|
||||
#define RFM22_gpio1_config_eire 0x05 // External Interrupt, rising edge (input)
|
||||
#define RFM22_gpio1_config_eisc 0x06 // External Interrupt, state change (input)
|
||||
#define RFM22_gpio1_config_ai 0x07 // ADC Analog Input
|
||||
#define RFM22_gpio1_config_atni 0x08 // Reserved (Analog Test N Input)
|
||||
#define RFM22_gpio1_config_atpi 0x09 // Reserved (Analog Test P Input)
|
||||
#define RFM22_gpio1_config_ddo 0x0A // Direct Digital Output
|
||||
#define RFM22_gpio1_config_dto 0x0B // Reserved (Digital Test Output)
|
||||
#define RFM22_gpio1_config_atno 0x0C // Reserved (Analog Test N Output)
|
||||
#define RFM22_gpio1_config_atpo 0x0D // Reserved (Analog Test P Output)
|
||||
#define RFM22_gpio1_config_rv 0xOE // Reference Voltage (output)
|
||||
#define RFM22_gpio1_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
|
||||
#define RFM22_gpio1_config_txd 0x10 // TX Data input for direct modulation (input)
|
||||
#define RFM22_gpio1_config_err 0x11 // External Retransmission Request (input)
|
||||
#define RFM22_gpio1_config_txstate 0x12 // TX State (output)
|
||||
#define RFM22_gpio1_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
|
||||
#define RFM22_gpio1_config_rxd 0x14 // RX Data (output)
|
||||
#define RFM22_gpio1_config_rxstate 0x15 // RX State (output)
|
||||
#define RFM22_gpio1_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
|
||||
#define RFM22_gpio1_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio1_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio1_config_vpd 0x19 // Valid Preamble Detected (output)
|
||||
#define RFM22_gpio1_config_ipd 0x1A // Invalid Preamble Detected (output)
|
||||
#define RFM22_gpio1_config_swd 0x1B // Sync Word Detected (output)
|
||||
#define RFM22_gpio1_config_cca 0x1C // Clear Channel Assessment (output)
|
||||
#define RFM22_gpio1_config_vdd 0x1D // VDD
|
||||
#define RFM22_gpio1_config_pup 0x20
|
||||
#define RFM22_gpio1_config_drv0 0x00 // output drive level
|
||||
#define RFM22_gpio1_config_drv1 0x40 // output drive level
|
||||
#define RFM22_gpio1_config_drv2 0x80 // output drive level
|
||||
#define RFM22_gpio1_config_drv3 0xC0 // output drive level
|
||||
|
||||
#define RFM22_gpio2_config 0x0D // R/W
|
||||
#define RFM22_gpio2_config_mc 0x00 // Microcontroller Clock (output)
|
||||
#define RFM22_gpio2_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
|
||||
#define RFM22_gpio2_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
|
||||
#define RFM22_gpio2_config_ddi 0x03 // Direct Digital Input
|
||||
#define RFM22_gpio2_config_eife 0x04 // External Interrupt, falling edge (input)
|
||||
#define RFM22_gpio2_config_eire 0x05 // External Interrupt, rising edge (input)
|
||||
#define RFM22_gpio2_config_eisc 0x06 // External Interrupt, state change (input)
|
||||
#define RFM22_gpio2_config_ai 0x07 // ADC Analog Input
|
||||
#define RFM22_gpio2_config_atni 0x08 // Reserved (Analog Test N Input)
|
||||
#define RFM22_gpio2_config_atpi 0x09 // Reserved (Analog Test P Input)
|
||||
#define RFM22_gpio2_config_ddo 0x0A // Direct Digital Output
|
||||
#define RFM22_gpio2_config_dto 0x0B // Reserved (Digital Test Output)
|
||||
#define RFM22_gpio2_config_atno 0x0C // Reserved (Analog Test N Output)
|
||||
#define RFM22_gpio2_config_atpo 0x0D // Reserved (Analog Test P Output)
|
||||
#define RFM22_gpio2_config_rv 0xOE // Reference Voltage (output)
|
||||
#define RFM22_gpio2_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
|
||||
#define RFM22_gpio2_config_txd 0x10 // TX Data input for direct modulation (input)
|
||||
#define RFM22_gpio2_config_err 0x11 // External Retransmission Request (input)
|
||||
#define RFM22_gpio2_config_txstate 0x12 // TX State (output)
|
||||
#define RFM22_gpio2_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
|
||||
#define RFM22_gpio2_config_rxd 0x14 // RX Data (output)
|
||||
#define RFM22_gpio2_config_rxstate 0x15 // RX State (output)
|
||||
#define RFM22_gpio2_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
|
||||
#define RFM22_gpio2_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio2_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio2_config_vpd 0x19 // Valid Preamble Detected (output)
|
||||
#define RFM22_gpio2_config_ipd 0x1A // Invalid Preamble Detected (output)
|
||||
#define RFM22_gpio2_config_swd 0x1B // Sync Word Detected (output)
|
||||
#define RFM22_gpio2_config_cca 0x1C // Clear Channel Assessment (output)
|
||||
#define RFM22_gpio2_config_vdd 0x1D // VDD
|
||||
#define RFM22_gpio2_config_pup 0x20
|
||||
#define RFM22_gpio2_config_drv0 0x00 // output drive level
|
||||
#define RFM22_gpio2_config_drv1 0x40 // output drive level
|
||||
#define RFM22_gpio2_config_drv2 0x80 // output drive level
|
||||
#define RFM22_gpio2_config_drv3 0xC0 // output drive level
|
||||
|
||||
#define RFM22_io_port_config 0x0E // R/W
|
||||
#define RFM22_io_port_extitst2 0x40 // External Interrupt Status. If the GPIO2 is programmed to be external interrupt sources then the status can be read here.
|
||||
#define RFM22_io_port_extitst1 0x20 // External Interrupt Status. If the GPIO1 is programmed to be external interrupt sources then the status can be read here.
|
||||
#define RFM22_io_port_extitst0 0x10 // External Interrupt Status. If the GPIO0 is programmed to be external interrupt sources then the status can be read here.
|
||||
#define RFM22_io_port_itsdo 0x08 // Interrupt Request Output on the SDO Pin. nIRQ output is present on the SDO pin if this bit is set and the nSEL input is inactive (high).
|
||||
#define RFM22_io_port_dio2 0x04 // Direct I/O for GPIO2. If the GPIO2 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO2 is configured to be a direct input then the value of the pin can be read here.
|
||||
#define RFM22_io_port_dio1 0x02 // Direct I/O for GPIO1. If the GPIO1 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO1 is configured to be a direct input then the value of the pin can be read here.
|
||||
#define RFM22_io_port_dio0 0x01 // Direct I/O for GPIO0. If the GPIO0 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO0 is configured to be a direct input then the value of the pin can be read here.
|
||||
#define RFM22_io_port_default 0x00 // GPIO pins are default
|
||||
|
||||
#define RFM22_adc_config 0x0F // R/W
|
||||
#define RFM22_ac_adcgain0 0x00
|
||||
#define RFM22_ac_adcgain1 0x01
|
||||
#define RFM22_ac_adcgain2 0x02
|
||||
#define RFM22_ac_adcgain3 0x03
|
||||
#define RFM22_ac_adcref_bg 0x00
|
||||
#define RFM22_ac_adcref_vdd3 0x08
|
||||
#define RFM22_ac_adcref_vdd2 0x0C
|
||||
#define RFM22_ac_adcsel_temp_sensor 0x00
|
||||
#define RFM22_ac_adcsel_gpio0 0x10
|
||||
#define RFM22_ac_adcsel_gpio1 0x20
|
||||
#define RFM22_ac_adcsel_gpio2 0x30
|
||||
#define RFM22_ac_adcsel_gpio01 0x40
|
||||
#define RFM22_ac_adcsel_gpio12 0x50
|
||||
#define RFM22_ac_adcsel_gpio02 0x60
|
||||
#define RFM22_ac_adcsel_gpio_gnd 0x70
|
||||
#define RFM22_ac_adcstartbusy 0x80
|
||||
|
||||
#define RFM22_adc_sensor_amp_offset 0x10 // R/W
|
||||
#define RFM22_asao_adcoffs_mask 0x0F // ADC Sensor Amplifier Offset. The offset can be calculated as Offset = adcoffs[2:0] x VDD/1000; MSB = adcoffs[3] = Sign bit.
|
||||
|
||||
#define RFM22_adc_value 0x11 // R .. Internal 8 bit ADC Output Value.
|
||||
|
||||
#define RFM22_temp_sensor_calib 0x12 // R/W
|
||||
#define RFM22_tsc_tstrim_mask 0x0F // Temperature Sensor Trim Value.
|
||||
#define RFM22_tsc_entstrim 0x10 // Temperature Sensor Trim Enable.
|
||||
#define RFM22_tsc_entsoffs 0x20 // Temperature Sensor Offset to Convert from K to ºC.
|
||||
#define RFM22_tsc_tsrange0 0x00 // Temperature Sensor Range Selection. –64C to +64C 0.5C resolution
|
||||
#define RFM22_tsc_tsrange1 0x40 // -40 to +85C with 1.0C resolution
|
||||
#define RFM22_tsc_tsrange2 0x80 // 0C to 85C with 0.5C resolution
|
||||
#define RFM22_tsc_tsrange3 0xC0 // -40F to 216F with 1.0F resolution
|
||||
|
||||
#define RFM22_temp_value_offset 0x13 // R/W
|
||||
|
||||
#define RFM22_wakeup_timer_period1 0x14 // R/W
|
||||
#define RFM22_wakeup_timer_period2 0x15 // R/W
|
||||
#define RFM22_wakeup_timer_period3 0x16 // R/W
|
||||
|
||||
#define RFM22_wakeup_timer_value1 0x17 // R
|
||||
#define RFM22_wakeup_timer_value2 0x18 // R
|
||||
|
||||
#define RFM22_low_dutycycle_mode_duration 0x19 // R/W
|
||||
#define RFM22_low_battery_detector_threshold 0x1A // R/W
|
||||
|
||||
#define RFM22_battery_volateg_level 0x1B // R
|
||||
|
||||
#define RFM22_if_filter_bandwidth 0x1C // R/W
|
||||
#define RFM22_iffbw_filset_mask 0x0F
|
||||
#define RFM22_iffbw_ndec_exp_mask 0x70
|
||||
#define RFM22_iffbw_dwn3_bypass 0x80
|
||||
|
||||
#define RFM22_afc_loop_gearshift_override 0x1D // R/W
|
||||
#define RFM22_afc_lp_gs_ovrd_afcgearl_mask 0x07 // AFC Low Gear Setting.
|
||||
#define RFM22_afc_lp_gs_ovrd_afcgearh_mask 0x38 // AFC High Gear Setting.
|
||||
#define RFM22_afc_lp_gs_ovrd_enafc 0x40 // AFC Enable.
|
||||
#define RFM22_afc_lp_gs_ovrd_afcbd 0x80 // If set, the tolerated AFC frequency error will be halved.
|
||||
|
||||
#define RFM22_afc_timing_control 0x1E // R/W
|
||||
|
||||
#define RFM22_clk_recovery_gearshift_override 0x1F // R/W
|
||||
#define RFM22_clk_recovery_oversampling_ratio 0x20 // R/W
|
||||
#define RFM22_clk_recovery_offset2 0x21 // R/W
|
||||
#define RFM22_clk_recovery_offset1 0x22 // R/W
|
||||
#define RFM22_clk_recovery_offset0 0x23 // R/W
|
||||
#define RFM22_clk_recovery_timing_loop_gain1 0x24 // R/W
|
||||
#define RFM22_clk_recovery_timing_loop_gain0 0x25 // R/W
|
||||
|
||||
#define RFM22_rssi 0x26 // R
|
||||
#define RFM22_rssi_threshold_clear_chan_indicator 0x27 // R/W
|
||||
|
||||
#define RFM22_antenna_diversity_register1 0x28 // R
|
||||
#define RFM22_antenna_diversity_register2 0x29 // R
|
||||
|
||||
#define RFM22_afc_limiter 0x2A // R/W .. AFC_pull_in_range = ±AFCLimiter[7:0] x (hbsel+1) x 625 Hz
|
||||
|
||||
#define RFM22_afc_correction_read 0x2B // R
|
||||
|
||||
#define RFM22_ook_counter_value1 0x2C // R/W
|
||||
#define RFM22_ook_counter_value2 0x2D // R/W
|
||||
|
||||
#define RFM22_slicer_peak_hold 0x2E // R/W
|
||||
|
||||
#define RFM22_data_access_control 0x30 // R/W
|
||||
#define RFM22_dac_crc_ccitt 0x00 //
|
||||
#define RFM22_dac_crc_crc16 0x01 //
|
||||
#define RFM22_dac_crc_iec16 0x02 //
|
||||
#define RFM22_dac_crc_biacheva 0x03 //
|
||||
#define RFM22_dac_encrc 0x04 // CRC Enable. Cyclic Redundancy Check generation is enabled if this bit is set.
|
||||
#define RFM22_dac_enpactx 0x08 // Enable Packet TX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpactx = 1 will enable automatic packet handling in the TX path. Register 30–4D allow for various configurations of the packet structure. Setting enpactx = 0 will not do any packet handling in the TX path. It will only transmit what is loaded to the FIFO.
|
||||
#define RFM22_dac_skip2ph 0x10 // Skip 2nd Phase of Preamble Detection. If set, we skip the second phase of the preamble detection (under certain conditions) if antenna diversity is enabled.
|
||||
#define RFM22_dac_crcdonly 0x20 // CRC Data Only Enable. When this bit is set to 1 the CRC is calculated on and checked against the packet data fields only.
|
||||
#define RFM22_dac_lsbfrst 0x40 // LSB First Enable. The LSB of the data will be transmitted/received first if this bit is set.
|
||||
#define RFM22_dac_enpacrx 0x80 // Enable Packet RX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpacrx = 1 will enable automatic packet handling in the RX path. Register 30–4D allow for various configurations of the packet structure. Setting enpacrx = 0 will not do any packet handling in the RX path. It will only receive everything after the sync word and fill up the RX FIFO.
|
||||
|
||||
#define RFM22_ezmac_status 0x31 // R
|
||||
#define RFM22_ezmac_status_pksent 0x01 // Packet Sent. A 1 a packet has been sent by the radio. (Same bit as in register 03, but reading it does not reset the IRQ)
|
||||
#define RFM22_ezmac_status_pktx 0x02 // Packet Transmitting. When 1 the radio is currently transmitting a packet.
|
||||
#define RFM22_ezmac_status_crcerror 0x04 // CRC Error. When 1 a Cyclic Redundancy Check error has been detected. (Same bit as in register 03, but reading it does not reset the IRQ)
|
||||
#define RFM22_ezmac_status_pkvalid 0x08 // Valid Packet Received. When a 1 a valid packet has been received by the receiver. (Same bit as in register 03, but reading it does not reset the IRQ)
|
||||
#define RFM22_ezmac_status_pkrx 0x10 // Packet Receiving. When 1 the radio is currently receiving a valid packet.
|
||||
#define RFM22_ezmac_status_pksrch 0x20 // Packet Searching. When 1 the radio is searching for a valid packet.
|
||||
#define RFM22_ezmac_status_rxcrc1 0x40 // If high, it indicates the last CRC received is all one’s. May indicated Transmitter underflow in case of CRC error.
|
||||
|
||||
#define RFM22_header_control1 0x32 // R/W
|
||||
#define RFM22_header_cntl1_bcen_none 0x00 // No broadcast address enable.
|
||||
#define RFM22_header_cntl1_bcen_0 0x10 // Broadcast address enable for header byte 0.
|
||||
#define RFM22_header_cntl1_bcen_1 0x20 // Broadcast address enable for header byte 1.
|
||||
#define RFM22_header_cntl1_bcen_2 0x40 // Broadcast address enable for header byte 2.
|
||||
#define RFM22_header_cntl1_bcen_3 0x80 // Broadcast address enable for header byte 3.
|
||||
#define RFM22_header_cntl1_hdch_none 0x00 // No Received Header check
|
||||
#define RFM22_header_cntl1_hdch_0 0x01 // Received Header check for byte 0.
|
||||
#define RFM22_header_cntl1_hdch_1 0x02 // Received Header check for byte 1.
|
||||
#define RFM22_header_cntl1_hdch_2 0x04 // Received Header check for byte 2.
|
||||
#define RFM22_header_cntl1_hdch_3 0x08 // Received Header check for byte 3.
|
||||
|
||||
#define RFM22_header_control2 0x33 // R/W
|
||||
#define RFM22_header_cntl2_prealen 0x01 // MSB of Preamble Length. See register Preamble Length.
|
||||
#define RFM22_header_cntl2_synclen_3 0x00 // Synchronization Word 3
|
||||
#define RFM22_header_cntl2_synclen_32 0x02 // Synchronization Word 3 followed by 2
|
||||
#define RFM22_header_cntl2_synclen_321 0x04 // Synchronization Word 3 followed by 2 followed by 1
|
||||
#define RFM22_header_cntl2_synclen_3210 0x06 // Synchronization Word 3 followed by 2 followed by 1 followed by 0
|
||||
#define RFM22_header_cntl2_fixpklen 0x08 // Fix Packet Length. When fixpklen = 1 the packet length (pklen[7:0]) is not included in the header. When fixpklen = 0 the packet length is included in the header.
|
||||
#define RFM22_header_cntl2_hdlen_none 0x00 // no header
|
||||
#define RFM22_header_cntl2_hdlen_3 0x10 // header 3
|
||||
#define RFM22_header_cntl2_hdlen_32 0x20 // header 3 and 2
|
||||
#define RFM22_header_cntl2_hdlen_321 0x30 // header 3 and 2 and 1
|
||||
#define RFM22_header_cntl2_hdlen_3210 0x40 // header 3 and 2 and 1 and 0
|
||||
#define RFM22_header_cntl2_skipsyn 0x80 // If high, the system will ignore the syncword search timeout reset. The chip will not return to searching for Preamble, but instead will remain searching for Sync word.
|
||||
|
||||
#define RFM22_preamble_length 0x34 // R/W
|
||||
|
||||
#define RFM22_preamble_detection_ctrl1 0x35 // R/W
|
||||
#define RFM22_pre_det_ctrl1_preath_mask 0xF8 // Number of nibbles processed during detection.
|
||||
#define RFM22_pre_det_ctrl1_rssi_offset_mask 0x07 // Value added as offset to RSSI calculation. Every increment in this register results in an increment of +4 dB in the RSSI.
|
||||
|
||||
#define RFM22_sync_word3 0x36 // R/W
|
||||
#define RFM22_sync_word2 0x37 // R/W
|
||||
#define RFM22_sync_word1 0x38 // R/W
|
||||
#define RFM22_sync_word0 0x39 // R/W
|
||||
|
||||
#define RFM22_transmit_header3 0x3A // R/W
|
||||
#define RFM22_transmit_header2 0x3B // R/W
|
||||
#define RFM22_transmit_header1 0x3C // R/W
|
||||
#define RFM22_transmit_header0 0x3D // R/W
|
||||
|
||||
#define RFM22_transmit_packet_length 0x3E // R/W
|
||||
|
||||
#define RFM22_check_header3 0x3F // R/W
|
||||
#define RFM22_check_header2 0x40 // R/W
|
||||
#define RFM22_check_header1 0x41 // R/W
|
||||
#define RFM22_check_header0 0x42 // R/W
|
||||
|
||||
#define RFM22_header_enable3 0x43 // R/W
|
||||
#define RFM22_header_enable2 0x44 // R/W
|
||||
#define RFM22_header_enable1 0x45 // R/W
|
||||
#define RFM22_header_enable0 0x46 // R/W
|
||||
|
||||
#define RFM22_received_header3 0x47 // R
|
||||
#define RFM22_received_header2 0x48 // R
|
||||
#define RFM22_received_header1 0x49 // R
|
||||
#define RFM22_received_header0 0x4A // R
|
||||
|
||||
#define RFM22_received_packet_length 0x4B // R
|
||||
|
||||
#define RFM22_adc8_control 0x4F // R/W
|
||||
/*
|
||||
#define RFM22_analog_test_bus 0x50 // R/W
|
||||
#define RFM22_digital_test_bus 0x51 // R/W
|
||||
#define RFM22_tx_ramp_control 0x52 // R/W
|
||||
#define RFM22_pll_tune_time 0x53 // R/W
|
||||
|
||||
#define RFM22_calibration_control 0x55 // R/W
|
||||
|
||||
#define RFM22_modem_test 0x56 // R/W
|
||||
|
||||
#define RFM22_chargepump_test 0x57 // R/W
|
||||
#define RFM22_chargepump_current_trimming_override 0x58 // R/W
|
||||
|
||||
#define RFM22_divider_current_trimming 0x59 // R/W
|
||||
|
||||
#define RFM22_vco_current_trimming 0x5A // R/W
|
||||
#define RFM22_vco_calibration_override 0x5B // R/W
|
||||
|
||||
#define RFM22_synthersizer_test 0x5C // R/W
|
||||
|
||||
#define RFM22_block_enable_override1 0x5D // R/W
|
||||
#define RFM22_block_enable_override2 0x5E // R/W
|
||||
#define RFM22_block_enable_override3 0x5F // R/W
|
||||
*/
|
||||
#define RFM22_channel_filter_coeff_addr 0x60 // R/W
|
||||
#define RFM22_ch_fil_coeff_ad_inv_pre_th_mask 0xF0 //
|
||||
#define RFM22_ch_fil_coeff_ad_chfiladd_mask 0x0F // Channel Filter Coefficient Look-up Table Address. The address for channel filter coefficients used in the RX path.
|
||||
|
||||
|
||||
//#define RFM22_channel_filter_coeff_value 0x61 // R/W
|
||||
|
||||
#define RFM22_xtal_osc_por_ctrl 0x62 // R/W
|
||||
#define RFM22_xtal_osc_por_ctrl_pwst_mask 0xE0 // Internal Power States of the Chip.
|
||||
#define RFM22_xtal_osc_por_ctrl_clkhyst 0x10 // Clock Hysteresis Setting.
|
||||
#define RFM22_xtal_osc_por_ctrl_enbias2x 0x08 // 2 Times Higher Bias Current Enable.
|
||||
#define RFM22_xtal_osc_por_ctrl_enamp2x 0x04 // 2 Times Higher Amplification Enable.
|
||||
#define RFM22_xtal_osc_por_ctrl_bufovr 0x02 // Output Buffer Enable Override.
|
||||
#define RFM22_xtal_osc_por_ctrl_enbuf 0x01 // Output Buffer Enable.
|
||||
/*
|
||||
#define RFM22_rc_osc_coarse_calbration_override 0x63 // R/W
|
||||
#define RFM22_rc_osc_fine_calbration_override 0x64 // R/W
|
||||
|
||||
#define RFM22_ldo_control_override 0x65 // R/W
|
||||
#define RFM22_ldo_level_setting 0x66 // R/W
|
||||
|
||||
#define RFM22_deltasigma_adc_tuning1 0x67 // R/W
|
||||
#define RFM22_deltasigma_adc_tuning2 0x68 // R/W
|
||||
*/
|
||||
#define RFM22_agc_override1 0x69 // R/W
|
||||
#define RFM22_agc_ovr1_sgi 0x40 // AGC Loop, Set Gain Increase. If set to 0 then gain increasing will not be allowed. If set to 1 then gain increasing is allowed, default is 0.
|
||||
#define RFM22_agc_ovr1_agcen 0x20 // Automatic Gain Control Enable. When this bit is set then the result of the control can be read out from bits [4:0], otherwise the gain can be controlled manually by writing into bits [4:0].
|
||||
#define RFM22_agc_ovr1_lnagain 0x10 // LNA Gain Select. 0 = min gain = 5dB, 1 = max gain = 25 dB.
|
||||
#define RFM22_agc_ovr1_pga_mask 0x0F // PGA Gain Override Value.
|
||||
|
||||
//#define RFM22_agc_override2 0x6A // R/W
|
||||
|
||||
//#define RFM22_gfsk_fir_coeff_addr 0x6B // R/W
|
||||
//#define RFM22_gfsk_fir_coeff_value 0x6C // R/W
|
||||
|
||||
#define RFM22_tx_power 0x6D // R/W
|
||||
#define RFM22_tx_pwr_txpow_0 0x00 // +1dBm .. 1.25mW
|
||||
#define RFM22_tx_pwr_txpow_1 0x01 // +2dBm .. 1.6mW
|
||||
#define RFM22_tx_pwr_txpow_2 0x02 // +5dBm .. 3.16mW
|
||||
#define RFM22_tx_pwr_txpow_3 0x03 // +8dBm .. 6.3mW
|
||||
#define RFM22_tx_pwr_txpow_4 0x04 // +11dBm .. 12.6mW
|
||||
#define RFM22_tx_pwr_txpow_5 0x05 // +14dBm .. 25mW
|
||||
#define RFM22_tx_pwr_txpow_6 0x06 // +17dBm .. 50mW
|
||||
#define RFM22_tx_pwr_txpow_7 0x07 // +20dBm .. 100mW
|
||||
#define RFM22_tx_pwr_lna_sw 0x08 // LNA Switch Controller. If set, lna_sw control from the digital will go high during TX modes, and low during other times. If reset, the digital control signal is low at all times.
|
||||
#define RFM22_tx_pwr_papeaklvl_0 0x10 // " "
|
||||
#define RFM22_tx_pwr_papeaklvl_1 0x20 // PA Peak Detect Level (direct from register). 00 = 6.5, 01 = 7, 10 = 7.5, 11 = 8, 00 = default
|
||||
#define RFM22_tx_pwr_papeaken 0x40 // PA Peak Detector Enable.
|
||||
#define RFM22_tx_pwr_papeakval 0x80 // PA Peak Detector Value Read Register. Reading a 1 in this register when the papeaken=1 then the PA drain voltage is too high and the match network needs adjusting for optimal efficiency.
|
||||
|
||||
#define RFM22_tx_data_rate1 0x6E // R/W
|
||||
#define RFM22_tx_data_rate0 0x6F // R/W
|
||||
|
||||
#define RFM22_modulation_mode_control1 0x70 // R/W
|
||||
#define RFM22_mmc1_enwhite 0x01 // Data Whitening is Enabled if this bit is set.
|
||||
#define RFM22_mmc1_enmanch 0x02 // Manchester Coding is Enabled if this bit is set.
|
||||
#define RFM22_mmc1_enmaninv 0x04 // Manchester Data Inversion is Enabled if this bit is set.
|
||||
#define RFM22_mmc1_manppol 0x08 // Manchester Preamble Polarity (will transmit a series of 1 if set, or series of 0 if reset).
|
||||
#define RFM22_mmc1_enphpwdn 0x10 // If set, the Packet Handler will be powered down when chip is in low power mode.
|
||||
#define RFM22_mmc1_txdtrtscale 0x20 // This bit should be set for Data Rates below 30 kbps.
|
||||
|
||||
#define RFM22_modulation_mode_control2 0x71 // R/W
|
||||
#define RFM22_mmc2_modtyp_mask 0x03 // Modulation type.
|
||||
#define RFM22_mmc2_modtyp_none 0x00 //
|
||||
#define RFM22_mmc2_modtyp_ook 0x01 //
|
||||
#define RFM22_mmc2_modtyp_fsk 0x02 //
|
||||
#define RFM22_mmc2_modtyp_gfsk 0x03 //
|
||||
#define RFM22_mmc2_fd 0x04 // MSB of Frequency Deviation Setting, see "Register 72h. Frequency Deviation".
|
||||
#define RFM22_mmc2_eninv 0x08 // Invert TX and RX Data.
|
||||
#define RFM22_mmc2_dtmod_mask 0x30 // Modulation source.
|
||||
#define RFM22_mmc2_dtmod_dm_gpio 0x00 //
|
||||
#define RFM22_mmc2_dtmod_dm_sdi 0x10 //
|
||||
#define RFM22_mmc2_dtmod_fifo 0x20 //
|
||||
#define RFM22_mmc2_dtmod_pn9 0x30 //
|
||||
#define RFM22_mmc2_trclk_mask 0xC0 // TX Data Clock Configuration.
|
||||
#define RFM22_mmc2_trclk_clk_none 0x00 //
|
||||
#define RFM22_mmc2_trclk_clk_gpio 0x40 //
|
||||
#define RFM22_mmc2_trclk_clk_sdo 0x80 //
|
||||
#define RFM22_mmc2_trclk_clk_nirq 0xC0 //
|
||||
|
||||
#define RFM22_frequency_deviation 0x72 // R/W
|
||||
|
||||
#define RFM22_frequency_offset1 0x73 // R/W
|
||||
#define RFM22_frequency_offset2 0x74 // R/W
|
||||
|
||||
#define RFM22_frequency_band_select 0x75 // R/W
|
||||
#define RFM22_fb_mask 0x1F
|
||||
#define RFM22_fbs_hbsel 0x20
|
||||
#define RFM22_fbs_sbse 0x40
|
||||
|
||||
#define RFM22_nominal_carrier_frequency1 0x76 // R/W
|
||||
#define RFM22_nominal_carrier_frequency0 0x77 // R/W
|
||||
|
||||
#define RFM22_frequency_hopping_channel_select 0x79 // R/W
|
||||
#define RFM22_frequency_hopping_step_size 0x7A // R/W
|
||||
|
||||
#define RFM22_tx_fifo_control1 0x7C // R/W .. TX FIFO Almost Full Threshold (0 - 63)
|
||||
#define RFM22_tx_fifo_control1_mask 0x3F
|
||||
|
||||
#define RFM22_tx_fifo_control2 0x7D // R/W .. TX FIFO Almost Empty Threshold (0 - 63)
|
||||
#define RFM22_tx_fifo_control2_mask 0x3F
|
||||
|
||||
#define RFM22_rx_fifo_control 0x7E // R/W .. RX FIFO Almost Full Threshold (0 - 63)
|
||||
#define RFM22_rx_fifo_control_mask 0x3F
|
||||
|
||||
#define RFM22_fifo_access 0x7F // R/W
|
||||
|
||||
// ************************************
|
||||
|
||||
typedef int16_t ( *t_rfm22_TxDataByteCallback ) (void);
|
||||
typedef bool ( *t_rfm22_RxDataCallback ) (void *data, uint8_t len);
|
||||
|
||||
// ************************************
|
||||
|
||||
uint32_t rfm22_minFrequency(void);
|
||||
uint32_t rfm22_maxFrequency(void);
|
||||
|
||||
void rfm22_setNominalCarrierFrequency(uint32_t frequency_hz);
|
||||
uint32_t rfm22_getNominalCarrierFrequency(void);
|
||||
|
||||
float rfm22_getFrequencyStepSize(void);
|
||||
|
||||
void rfm22_setFreqHopChannel(uint8_t channel);
|
||||
uint8_t rfm22_freqHopChannel(void);
|
||||
|
||||
uint32_t rfm22_freqHopSize(void);
|
||||
|
||||
void rfm22_setDatarate(uint32_t datarate_bps, bool data_whitening);
|
||||
uint32_t rfm22_getDatarate(void);
|
||||
|
||||
void rfm22_setRxMode(uint8_t mode, bool multi_packet_mode);
|
||||
|
||||
int8_t rfm22_getRSSI(void);
|
||||
|
||||
int8_t rfm22_receivedRSSI(void);
|
||||
int32_t rfm22_receivedAFCHz(void);
|
||||
uint16_t rfm22_receivedLength(void);
|
||||
uint8_t * rfm22_receivedPointer(void);
|
||||
void rfm22_receivedDone(void);
|
||||
|
||||
int32_t rfm22_sendData(void *data, uint16_t length, bool send_immediately);
|
||||
|
||||
void rfm22_setFreqCalibration(uint8_t value);
|
||||
uint8_t rfm22_getFreqCalibration(void);
|
||||
|
||||
void rfm22_setTxPower(uint8_t tx_pwr);
|
||||
uint8_t rfm22_getTxPower(void);
|
||||
|
||||
void rfm22_setTxStream(void); // TEST ONLY
|
||||
|
||||
void rfm22_setTxNormal(void);
|
||||
void rfm22_setTxCarrierMode(void);
|
||||
void rfm22_setTxPNMode(void);
|
||||
|
||||
int8_t rfm22_currentMode(void);
|
||||
bool rfm22_transmitting(void);
|
||||
|
||||
bool rfm22_channelIsClear(void);
|
||||
|
||||
bool rfm22_txReady(void);
|
||||
|
||||
void rfm22_1ms_tick(void);
|
||||
|
||||
void rfm22_TxDataByte_SetCallback(t_rfm22_TxDataByteCallback new_function);
|
||||
void rfm22_RxData_SetCallback(t_rfm22_RxDataCallback new_function);
|
||||
|
||||
int rfm22_init_scan_spectrum(uint32_t min_frequency_hz, uint32_t max_frequency_hz);
|
||||
int rfm22_init_tx_stream(uint32_t min_frequency_hz, uint32_t max_frequency_hz);
|
||||
int rfm22_init_rx_stream(uint32_t min_frequency_hz, uint32_t max_frequency_hz);
|
||||
int rfm22_init_normal(uint32_t id, uint32_t min_frequency_hz, uint32_t max_frequency_hz, uint32_t freq_hop_step_size);
|
||||
|
||||
#endif /* PIOS_RFM22B_PRIV_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_RFM22B Radio Functions
|
||||
* @brief PIOS interface for RFM22B Radio
|
||||
* @{
|
||||
*
|
||||
* @file pios_rfm22b_priv.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief RFM22B private definitions.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_RFM22B_PRIV_H
|
||||
#define PIOS_RFM22B_PRIV_H
|
||||
|
||||
#include <pios.h>
|
||||
#include "fifo_buffer.h"
|
||||
#include "pios_rfm22b.h"
|
||||
|
||||
extern const struct pios_com_driver pios_rfm22b_com_driver;
|
||||
|
||||
// ************************************
|
||||
|
||||
#define RFM22_DEVICE_VERSION_V2 0x02
|
||||
#define RFM22_DEVICE_VERSION_A0 0x04
|
||||
#define RFM22_DEVICE_VERSION_B1 0x06
|
||||
|
||||
// ************************************
|
||||
|
||||
#define RFM22_MIN_CARRIER_FREQUENCY_HZ 240000000ul
|
||||
#define RFM22_MAX_CARRIER_FREQUENCY_HZ 930000000ul
|
||||
|
||||
// ************************************
|
||||
|
||||
enum { RX_SCAN_SPECTRUM = 0,
|
||||
RX_WAIT_PREAMBLE_MODE,
|
||||
RX_WAIT_SYNC_MODE,
|
||||
RX_DATA_MODE,
|
||||
TX_DATA_MODE,
|
||||
TX_STREAM_MODE,
|
||||
TX_CARRIER_MODE,
|
||||
TX_PN_MODE};
|
||||
|
||||
// ************************************
|
||||
|
||||
#define BIT0 (1u << 0)
|
||||
#define BIT1 (1u << 1)
|
||||
#define BIT2 (1u << 2)
|
||||
#define BIT3 (1u << 3)
|
||||
#define BIT4 (1u << 4)
|
||||
#define BIT5 (1u << 5)
|
||||
#define BIT6 (1u << 6)
|
||||
#define BIT7 (1u << 7)
|
||||
|
||||
// ************************************
|
||||
|
||||
#define RFM22_DEVICE_TYPE 0x00 // R
|
||||
#define RFM22_DT_MASK 0x1F
|
||||
|
||||
#define RFM22_DEVICE_VERSION 0x01 // R
|
||||
#define RFM22_DV_MASK 0x1F
|
||||
|
||||
#define RFM22_device_status 0x02 // R
|
||||
#define RFM22_ds_cps_mask 0x03 // Chip Power State mask
|
||||
#define RFM22_ds_cps_idle 0x00 // IDLE Chip Power State
|
||||
#define RFM22_ds_cps_rx 0x01 // RX Chip Power State
|
||||
#define RFM22_ds_cps_tx 0x02 // TX Chip Power State
|
||||
//#define RFM22_ds_lockdet 0x04 //
|
||||
//#define RFM22_ds_freqerr 0x08 //
|
||||
#define RFM22_ds_headerr 0x10 // Header Error Status. Indicates if the received packet has a header check error
|
||||
#define RFM22_ds_rxffem 0x20 // RX FIFO Empty Status
|
||||
#define RFM22_ds_ffunfl 0x40 // RX/TX FIFO Underflow Status
|
||||
#define RFM22_ds_ffovfl 0x80 // RX/TX FIFO Overflow Status
|
||||
|
||||
#define RFM22_interrupt_status1 0x03 // R
|
||||
#define RFM22_is1_icrerror BIT0 // CRC Error. When set to 1 the cyclic redundancy check is failed.
|
||||
#define RFM22_is1_ipkvalid BIT1 // Valid Packet Received.When set to 1 a valid packet has been received.
|
||||
#define RFM22_is1_ipksent BIT2 // Packet Sent Interrupt. When set to1 a valid packet has been transmitted.
|
||||
#define RFM22_is1_iext BIT3 // External Interrupt. When set to 1 an interrupt occurred on one of the GPIO’s if it is programmed so. The status can be checked in register 0Eh. See GPIOx Configuration section for the details.
|
||||
#define RFM22_is1_irxffafull BIT4 // RX FIFO Almost Full.When set to 1 the RX FIFO has met its almost full threshold and needs to be read by the microcontroller.
|
||||
#define RFM22_is1_ixtffaem BIT5 // TX FIFO Almost Empty. When set to 1 the TX FIFO is almost empty and needs to be filled.
|
||||
#define RFM22_is1_itxffafull BIT6 // TX FIFO Almost Full. When set to 1 the TX FIFO has met its almost full threshold and needs to be transmitted.
|
||||
#define RFM22_is1_ifferr BIT7 // FIFO Underflow/Overflow Error. When set to 1 the TX or RX FIFO has overflowed or underflowed.
|
||||
|
||||
#define RFM22_interrupt_status2 0x04 // R
|
||||
#define RFM22_is2_ipor BIT0 // Power-on-Reset (POR). When the chip detects a Power on Reset above the desired setting this bit will be set to 1.
|
||||
#define RFM22_is2_ichiprdy BIT1 // Chip Ready (XTAL). When a chip ready event has been detected this bit will be set to 1.
|
||||
#define RFM22_is2_ilbd BIT2 // Low Battery Detect. When a low battery event is been detected this bit will be set to 1. This interrupt event is saved even if it is not enabled by the mask register bit and causes an interrupt after it is enabled.
|
||||
#define RFM22_is2_iwut BIT3 // Wake-Up-Timer. On the expiration of programmed wake-up timer this bit will be set to 1.
|
||||
#define RFM22_is2_irssi BIT4 // RSSI. When RSSI level exceeds the programmed threshold this bit will be set to 1.
|
||||
#define RFM22_is2_ipreainval BIT5 // Invalid Preamble Detected. When the preamble is not found within a period of time set by the invalid preamble detection threshold in Register 54h, this bit will be set to 1.
|
||||
#define RFM22_is2_ipreaval BIT6 // Valid Preamble Detected. When a preamble is detected this bit will be set to 1.
|
||||
#define RFM22_is2_iswdet BIT7 // Sync Word Detected. When a sync word is detected this bit will be set to 1.
|
||||
|
||||
#define RFM22_interrupt_enable1 0x05 // R/W
|
||||
#define RFM22_ie1_encrcerror BIT0 // Enable CRC Error. When set to 1 the CRC Error interrupt will be enabled.
|
||||
#define RFM22_ie1_enpkvalid BIT1 // Enable Valid Packet Received. When ipkvalid = 1 the Valid Packet Received Interrupt will be enabled.
|
||||
#define RFM22_ie1_enpksent BIT2 // Enable Packet Sent. When ipksent =1 the Packet Sense Interrupt will be enabled.
|
||||
#define RFM22_ie1_enext BIT3 // Enable External Interrupt. When set to 1 the External Interrupt will be enabled.
|
||||
#define RFM22_ie1_enrxffafull BIT4 // Enable RX FIFO Almost Full. When set to 1 the RX FIFO Almost Full interrupt will be enabled.
|
||||
#define RFM22_ie1_entxffaem BIT5 // Enable TX FIFO Almost Empty. When set to 1 the TX FIFO Almost Empty interrupt will be enabled.
|
||||
#define RFM22_ie1_entxffafull BIT6 // Enable TX FIFO Almost Full. When set to 1 the TX FIFO Almost Full interrupt will be enabled.
|
||||
#define RFM22_ie1_enfferr BIT7 // Enable FIFO Underflow/Overflow. When set to 1 the FIFO Underflow/Overflow interrupt will be enabled.
|
||||
|
||||
#define RFM22_interrupt_enable2 0x06 // R/W
|
||||
#define RFM22_ie2_enpor BIT0 // Enable POR. When set to 1 the POR interrupt will be enabled.
|
||||
#define RFM22_ie2_enchiprdy BIT1 // Enable Chip Ready (XTAL). When set to 1 the Chip Ready interrupt will be enabled.
|
||||
#define RFM22_ie2_enlbd BIT2 // Enable Low Battery Detect. When set to 1 the Low Battery Detect interrupt will be enabled.
|
||||
#define RFM22_ie2_enwut BIT3 // Enable Wake-Up Timer. When set to 1 the Wake-Up Timer interrupt will be enabled.
|
||||
#define RFM22_ie2_enrssi BIT4 // Enable RSSI. When set to 1 the RSSI Interrupt will be enabled.
|
||||
#define RFM22_ie2_enpreainval BIT5 // Enable Invalid Preamble Detected. When mpreadet =1 the Invalid Preamble Detected Interrupt will be enabled.
|
||||
#define RFM22_ie2_enpreaval BIT6 // Enable Valid Preamble Detected. When mpreadet =1 the Valid Preamble Detected Interrupt will be enabled.
|
||||
#define RFM22_ie2_enswdet BIT7 // Enable Sync Word Detected. When mpreadet =1 the Preamble Detected Interrupt will be enabled.
|
||||
|
||||
#define RFM22_op_and_func_ctrl1 0x07 // R/W
|
||||
#define RFM22_opfc1_xton 0x01 // READY Mode (Xtal is ON).
|
||||
#define RFM22_opfc1_pllon 0x02 // TUNE Mode (PLL is ON). When pllon = 1 the PLL will remain enabled in Idle State. This will for faster turn-around time at the cost of increased current consumption in Idle State.
|
||||
#define RFM22_opfc1_rxon 0x04 // RX on in Manual Receiver Mode. Automatically cleared if Multiple Packets config. is disabled and a valid packet received.
|
||||
#define RFM22_opfc1_txon 0x08 // TX on in Manual Transmit Mode. Automatically cleared in FIFO mode once the packet is sent. Transmission can be aborted during packet transmission, however, when no data has been sent yet, transmission can only be aborted after the device is programmed to “unmodulated carrier” ("Register 71h. Modulation Mode Control 2").
|
||||
#define RFM22_opfc1_x32ksel 0x10 // 32,768 kHz Crystal Oscillator Select. 0: RC oscillator 1: 32 kHz crystal
|
||||
#define RFM22_opfc1_enwt 0x20 // Enable Wake-Up-Timer. Enabled when enwt = 1. If the Wake-up-Timer function is enabled it will operate in any mode and notify the microcontroller through the GPIO interrupt when the timer expires.
|
||||
#define RFM22_opfc1_enlbd 0x40 // Enable Low Battery Detect. When this bit is set to 1 the Low Battery Detector circuit and threshold comparison will be enabled.
|
||||
#define RFM22_opfc1_swres 0x80 // Software Register Reset Bit. This bit may be used to reset all registers simultaneously to a DEFAULT state, without the need for sequentially writing to each individual register. The RESET is accomplished by setting swres = 1. This bit will be automatically cleared.
|
||||
|
||||
#define RFM22_op_and_func_ctrl2 0x08 // R/W
|
||||
#define RFM22_opfc2_ffclrtx 0x01 // TX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrtx =1 followed by ffclrtx = 0 will clear the contents of the TX FIFO.
|
||||
#define RFM22_opfc2_ffclrrx 0x02 // RX FIFO Reset/Clear. This has to be a two writes operation: Setting ffclrrx =1 followed by ffclrrx = 0 will clear the contents of the RX FIFO.
|
||||
#define RFM22_opfc2_enldm 0x04 // Enable Low Duty Cycle Mode. If this bit is set to 1 then the chip turns on the RX regularly. The frequency should be set in the Wake-Up Timer Period register, while the minimum ON time should be set in the Low-Duty Cycle Mode Duration register. The FIFO mode should be enabled also.
|
||||
#define RFM22_opfc2_autotx 0x08 // Automatic Transmission. When autotx = 1 the transceiver will enter automatically TX State when the FIFO is almost full. When the FIFO is empty it will automatically return to the Idle State.
|
||||
#define RFM22_opfc2_rxmpk 0x10 // RX Multi Packet. When the chip is selected to use FIFO Mode (dtmod[1:0]) and RX Packet Handling (enpacrx) then it will fill up the FIFO with multiple valid packets if this bit is set, otherwise the transceiver will automatically leave the RX State after the first valid packet has been received.
|
||||
#define RFM22_opfc2_antdiv_mask 0xE0 // Enable Antenna Diversity. The GPIO must be configured for Antenna Diversity for the algorithm to work properly.
|
||||
|
||||
#define RFM22_xtal_osc_load_cap 0x09 // R/W
|
||||
#define RFM22_xolc_xlc_mask 0x7F // Tuning Capacitance for the 30 MHz XTAL.
|
||||
#define RFM22_xolc_xtalshft 0x80 // Additional capacitance to course shift the frequency if xlc[6:0] is not sufficient. Not binary with xlc[6:0].
|
||||
|
||||
#define RFM22_cpu_output_clk 0x0A // R/W
|
||||
#define RFM22_coc_30MHz 0x00
|
||||
#define RFM22_coc_15MHz 0x01
|
||||
#define RFM22_coc_10MHz 0x02
|
||||
#define RFM22_coc_4MHz 0x03
|
||||
#define RFM22_coc_3MHz 0x04
|
||||
#define RFM22_coc_2MHz 0x05
|
||||
#define RFM22_coc_1MHz 0x06
|
||||
#define RFM22_coc_32768Hz 0x07
|
||||
#define RFM22_coc_enlfc 0x08
|
||||
#define RFM22_coc_0cycle 0x00
|
||||
#define RFM22_coc_128cycles 0x10
|
||||
#define RFM22_coc_256cycles 0x20
|
||||
#define RFM22_coc_512cycles 0x30
|
||||
|
||||
#define RFM22_gpio0_config 0x0B // R/W
|
||||
#define RFM22_gpio0_config_por 0x00 // Power-On-Reset (output)
|
||||
#define RFM22_gpio0_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
|
||||
#define RFM22_gpio0_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
|
||||
#define RFM22_gpio0_config_ddi 0x03 // Direct Digital Input
|
||||
#define RFM22_gpio0_config_eife 0x04 // External Interrupt, falling edge (input)
|
||||
#define RFM22_gpio0_config_eire 0x05 // External Interrupt, rising edge (input)
|
||||
#define RFM22_gpio0_config_eisc 0x06 // External Interrupt, state change (input)
|
||||
#define RFM22_gpio0_config_ai 0x07 // ADC Analog Input
|
||||
#define RFM22_gpio0_config_atni 0x08 // Reserved (Analog Test N Input)
|
||||
#define RFM22_gpio0_config_atpi 0x09 // Reserved (Analog Test P Input)
|
||||
#define RFM22_gpio0_config_ddo 0x0A // Direct Digital Output
|
||||
#define RFM22_gpio0_config_dto 0x0B // Reserved (Digital Test Output)
|
||||
#define RFM22_gpio0_config_atno 0x0C // Reserved (Analog Test N Output)
|
||||
#define RFM22_gpio0_config_atpo 0x0D // Reserved (Analog Test P Output)
|
||||
#define RFM22_gpio0_config_rv 0xOE // Reference Voltage (output)
|
||||
#define RFM22_gpio0_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
|
||||
#define RFM22_gpio0_config_txd 0x10 // TX Data input for direct modulation (input)
|
||||
#define RFM22_gpio0_config_err 0x11 // External Retransmission Request (input)
|
||||
#define RFM22_gpio0_config_txstate 0x12 // TX State (output)
|
||||
#define RFM22_gpio0_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
|
||||
#define RFM22_gpio0_config_rxd 0x14 // RX Data (output)
|
||||
#define RFM22_gpio0_config_rxstate 0x15 // RX State (output)
|
||||
#define RFM22_gpio0_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
|
||||
#define RFM22_gpio0_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio0_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio0_config_vpd 0x19 // Valid Preamble Detected (output)
|
||||
#define RFM22_gpio0_config_ipd 0x1A // Invalid Preamble Detected (output)
|
||||
#define RFM22_gpio0_config_swd 0x1B // Sync Word Detected (output)
|
||||
#define RFM22_gpio0_config_cca 0x1C // Clear Channel Assessment (output)
|
||||
#define RFM22_gpio0_config_vdd 0x1D // VDD
|
||||
#define RFM22_gpio0_config_pup 0x20
|
||||
#define RFM22_gpio0_config_drv0 0x00 // output drive level
|
||||
#define RFM22_gpio0_config_drv1 0x40 // output drive level
|
||||
#define RFM22_gpio0_config_drv2 0x80 // output drive level
|
||||
#define RFM22_gpio0_config_drv3 0xC0 // output drive level
|
||||
|
||||
#define RFM22_gpio1_config 0x0C // R/W
|
||||
#define RFM22_gpio1_config_ipor 0x00 // Inverted Power-On-Reset (output)
|
||||
#define RFM22_gpio1_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
|
||||
#define RFM22_gpio1_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
|
||||
#define RFM22_gpio1_config_ddi 0x03 // Direct Digital Input
|
||||
#define RFM22_gpio1_config_eife 0x04 // External Interrupt, falling edge (input)
|
||||
#define RFM22_gpio1_config_eire 0x05 // External Interrupt, rising edge (input)
|
||||
#define RFM22_gpio1_config_eisc 0x06 // External Interrupt, state change (input)
|
||||
#define RFM22_gpio1_config_ai 0x07 // ADC Analog Input
|
||||
#define RFM22_gpio1_config_atni 0x08 // Reserved (Analog Test N Input)
|
||||
#define RFM22_gpio1_config_atpi 0x09 // Reserved (Analog Test P Input)
|
||||
#define RFM22_gpio1_config_ddo 0x0A // Direct Digital Output
|
||||
#define RFM22_gpio1_config_dto 0x0B // Reserved (Digital Test Output)
|
||||
#define RFM22_gpio1_config_atno 0x0C // Reserved (Analog Test N Output)
|
||||
#define RFM22_gpio1_config_atpo 0x0D // Reserved (Analog Test P Output)
|
||||
#define RFM22_gpio1_config_rv 0xOE // Reference Voltage (output)
|
||||
#define RFM22_gpio1_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
|
||||
#define RFM22_gpio1_config_txd 0x10 // TX Data input for direct modulation (input)
|
||||
#define RFM22_gpio1_config_err 0x11 // External Retransmission Request (input)
|
||||
#define RFM22_gpio1_config_txstate 0x12 // TX State (output)
|
||||
#define RFM22_gpio1_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
|
||||
#define RFM22_gpio1_config_rxd 0x14 // RX Data (output)
|
||||
#define RFM22_gpio1_config_rxstate 0x15 // RX State (output)
|
||||
#define RFM22_gpio1_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
|
||||
#define RFM22_gpio1_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio1_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio1_config_vpd 0x19 // Valid Preamble Detected (output)
|
||||
#define RFM22_gpio1_config_ipd 0x1A // Invalid Preamble Detected (output)
|
||||
#define RFM22_gpio1_config_swd 0x1B // Sync Word Detected (output)
|
||||
#define RFM22_gpio1_config_cca 0x1C // Clear Channel Assessment (output)
|
||||
#define RFM22_gpio1_config_vdd 0x1D // VDD
|
||||
#define RFM22_gpio1_config_pup 0x20
|
||||
#define RFM22_gpio1_config_drv0 0x00 // output drive level
|
||||
#define RFM22_gpio1_config_drv1 0x40 // output drive level
|
||||
#define RFM22_gpio1_config_drv2 0x80 // output drive level
|
||||
#define RFM22_gpio1_config_drv3 0xC0 // output drive level
|
||||
|
||||
#define RFM22_gpio2_config 0x0D // R/W
|
||||
#define RFM22_gpio2_config_mc 0x00 // Microcontroller Clock (output)
|
||||
#define RFM22_gpio2_config_wut 0x01 // Wake-Up Timer: 1 when WUT has expired (output)
|
||||
#define RFM22_gpio2_config_lbd 0x02 // Low Battery Detect: 1 when battery is below threshold setting (output)
|
||||
#define RFM22_gpio2_config_ddi 0x03 // Direct Digital Input
|
||||
#define RFM22_gpio2_config_eife 0x04 // External Interrupt, falling edge (input)
|
||||
#define RFM22_gpio2_config_eire 0x05 // External Interrupt, rising edge (input)
|
||||
#define RFM22_gpio2_config_eisc 0x06 // External Interrupt, state change (input)
|
||||
#define RFM22_gpio2_config_ai 0x07 // ADC Analog Input
|
||||
#define RFM22_gpio2_config_atni 0x08 // Reserved (Analog Test N Input)
|
||||
#define RFM22_gpio2_config_atpi 0x09 // Reserved (Analog Test P Input)
|
||||
#define RFM22_gpio2_config_ddo 0x0A // Direct Digital Output
|
||||
#define RFM22_gpio2_config_dto 0x0B // Reserved (Digital Test Output)
|
||||
#define RFM22_gpio2_config_atno 0x0C // Reserved (Analog Test N Output)
|
||||
#define RFM22_gpio2_config_atpo 0x0D // Reserved (Analog Test P Output)
|
||||
#define RFM22_gpio2_config_rv 0xOE // Reference Voltage (output)
|
||||
#define RFM22_gpio2_config_dclk 0x0F // TX/RX Data CLK output to be used in conjunction with TX/RX Data pin (output)
|
||||
#define RFM22_gpio2_config_txd 0x10 // TX Data input for direct modulation (input)
|
||||
#define RFM22_gpio2_config_err 0x11 // External Retransmission Request (input)
|
||||
#define RFM22_gpio2_config_txstate 0x12 // TX State (output)
|
||||
#define RFM22_gpio2_config_txfifoaf 0x13 // TX FIFO Almost Full (output)
|
||||
#define RFM22_gpio2_config_rxd 0x14 // RX Data (output)
|
||||
#define RFM22_gpio2_config_rxstate 0x15 // RX State (output)
|
||||
#define RFM22_gpio2_config_rxfifoaf 0x16 // RX FIFO Almost Full (output)
|
||||
#define RFM22_gpio2_config_antswt1 0x17 // Antenna 1 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio2_config_antswt2 0x18 // Antenna 2 Switch used for antenna diversity (output)
|
||||
#define RFM22_gpio2_config_vpd 0x19 // Valid Preamble Detected (output)
|
||||
#define RFM22_gpio2_config_ipd 0x1A // Invalid Preamble Detected (output)
|
||||
#define RFM22_gpio2_config_swd 0x1B // Sync Word Detected (output)
|
||||
#define RFM22_gpio2_config_cca 0x1C // Clear Channel Assessment (output)
|
||||
#define RFM22_gpio2_config_vdd 0x1D // VDD
|
||||
#define RFM22_gpio2_config_pup 0x20
|
||||
#define RFM22_gpio2_config_drv0 0x00 // output drive level
|
||||
#define RFM22_gpio2_config_drv1 0x40 // output drive level
|
||||
#define RFM22_gpio2_config_drv2 0x80 // output drive level
|
||||
#define RFM22_gpio2_config_drv3 0xC0 // output drive level
|
||||
|
||||
#define RFM22_io_port_config 0x0E // R/W
|
||||
#define RFM22_io_port_extitst2 0x40 // External Interrupt Status. If the GPIO2 is programmed to be external interrupt sources then the status can be read here.
|
||||
#define RFM22_io_port_extitst1 0x20 // External Interrupt Status. If the GPIO1 is programmed to be external interrupt sources then the status can be read here.
|
||||
#define RFM22_io_port_extitst0 0x10 // External Interrupt Status. If the GPIO0 is programmed to be external interrupt sources then the status can be read here.
|
||||
#define RFM22_io_port_itsdo 0x08 // Interrupt Request Output on the SDO Pin. nIRQ output is present on the SDO pin if this bit is set and the nSEL input is inactive (high).
|
||||
#define RFM22_io_port_dio2 0x04 // Direct I/O for GPIO2. If the GPIO2 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO2 is configured to be a direct input then the value of the pin can be read here.
|
||||
#define RFM22_io_port_dio1 0x02 // Direct I/O for GPIO1. If the GPIO1 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO1 is configured to be a direct input then the value of the pin can be read here.
|
||||
#define RFM22_io_port_dio0 0x01 // Direct I/O for GPIO0. If the GPIO0 is configured to be a direct output then the value on the GPIO pin can be set here. If the GPIO0 is configured to be a direct input then the value of the pin can be read here.
|
||||
#define RFM22_io_port_default 0x00 // GPIO pins are default
|
||||
|
||||
#define RFM22_adc_config 0x0F // R/W
|
||||
#define RFM22_ac_adcgain0 0x00
|
||||
#define RFM22_ac_adcgain1 0x01
|
||||
#define RFM22_ac_adcgain2 0x02
|
||||
#define RFM22_ac_adcgain3 0x03
|
||||
#define RFM22_ac_adcref_bg 0x00
|
||||
#define RFM22_ac_adcref_vdd3 0x08
|
||||
#define RFM22_ac_adcref_vdd2 0x0C
|
||||
#define RFM22_ac_adcsel_temp_sensor 0x00
|
||||
#define RFM22_ac_adcsel_gpio0 0x10
|
||||
#define RFM22_ac_adcsel_gpio1 0x20
|
||||
#define RFM22_ac_adcsel_gpio2 0x30
|
||||
#define RFM22_ac_adcsel_gpio01 0x40
|
||||
#define RFM22_ac_adcsel_gpio12 0x50
|
||||
#define RFM22_ac_adcsel_gpio02 0x60
|
||||
#define RFM22_ac_adcsel_gpio_gnd 0x70
|
||||
#define RFM22_ac_adcstartbusy 0x80
|
||||
|
||||
#define RFM22_adc_sensor_amp_offset 0x10 // R/W
|
||||
#define RFM22_asao_adcoffs_mask 0x0F // ADC Sensor Amplifier Offset. The offset can be calculated as Offset = adcoffs[2:0] x VDD/1000; MSB = adcoffs[3] = Sign bit.
|
||||
|
||||
#define RFM22_adc_value 0x11 // R .. Internal 8 bit ADC Output Value.
|
||||
|
||||
#define RFM22_temp_sensor_calib 0x12 // R/W
|
||||
#define RFM22_tsc_tstrim_mask 0x0F // Temperature Sensor Trim Value.
|
||||
#define RFM22_tsc_entstrim 0x10 // Temperature Sensor Trim Enable.
|
||||
#define RFM22_tsc_entsoffs 0x20 // Temperature Sensor Offset to Convert from K to ºC.
|
||||
#define RFM22_tsc_tsrange0 0x00 // Temperature Sensor Range Selection. –64C to +64C 0.5C resolution
|
||||
#define RFM22_tsc_tsrange1 0x40 // -40 to +85C with 1.0C resolution
|
||||
#define RFM22_tsc_tsrange2 0x80 // 0C to 85C with 0.5C resolution
|
||||
#define RFM22_tsc_tsrange3 0xC0 // -40F to 216F with 1.0F resolution
|
||||
|
||||
#define RFM22_temp_value_offset 0x13 // R/W
|
||||
|
||||
#define RFM22_wakeup_timer_period1 0x14 // R/W
|
||||
#define RFM22_wakeup_timer_period2 0x15 // R/W
|
||||
#define RFM22_wakeup_timer_period3 0x16 // R/W
|
||||
|
||||
#define RFM22_wakeup_timer_value1 0x17 // R
|
||||
#define RFM22_wakeup_timer_value2 0x18 // R
|
||||
|
||||
#define RFM22_low_dutycycle_mode_duration 0x19 // R/W
|
||||
#define RFM22_low_battery_detector_threshold 0x1A // R/W
|
||||
|
||||
#define RFM22_battery_volateg_level 0x1B // R
|
||||
|
||||
#define RFM22_if_filter_bandwidth 0x1C // R/W
|
||||
#define RFM22_iffbw_filset_mask 0x0F
|
||||
#define RFM22_iffbw_ndec_exp_mask 0x70
|
||||
#define RFM22_iffbw_dwn3_bypass 0x80
|
||||
|
||||
#define RFM22_afc_loop_gearshift_override 0x1D // R/W
|
||||
#define RFM22_afc_lp_gs_ovrd_afcgearl_mask 0x07 // AFC Low Gear Setting.
|
||||
#define RFM22_afc_lp_gs_ovrd_afcgearh_mask 0x38 // AFC High Gear Setting.
|
||||
#define RFM22_afc_lp_gs_ovrd_enafc 0x40 // AFC Enable.
|
||||
#define RFM22_afc_lp_gs_ovrd_afcbd 0x80 // If set, the tolerated AFC frequency error will be halved.
|
||||
|
||||
#define RFM22_afc_timing_control 0x1E // R/W
|
||||
|
||||
#define RFM22_clk_recovery_gearshift_override 0x1F // R/W
|
||||
#define RFM22_clk_recovery_oversampling_ratio 0x20 // R/W
|
||||
#define RFM22_clk_recovery_offset2 0x21 // R/W
|
||||
#define RFM22_clk_recovery_offset1 0x22 // R/W
|
||||
#define RFM22_clk_recovery_offset0 0x23 // R/W
|
||||
#define RFM22_clk_recovery_timing_loop_gain1 0x24 // R/W
|
||||
#define RFM22_clk_recovery_timing_loop_gain0 0x25 // R/W
|
||||
|
||||
#define RFM22_rssi 0x26 // R
|
||||
#define RFM22_rssi_threshold_clear_chan_indicator 0x27 // R/W
|
||||
|
||||
#define RFM22_antenna_diversity_register1 0x28 // R
|
||||
#define RFM22_antenna_diversity_register2 0x29 // R
|
||||
|
||||
#define RFM22_afc_limiter 0x2A // R/W .. AFC_pull_in_range = ±AFCLimiter[7:0] x (hbsel+1) x 625 Hz
|
||||
|
||||
#define RFM22_afc_correction_read 0x2B // R
|
||||
|
||||
#define RFM22_ook_counter_value1 0x2C // R/W
|
||||
#define RFM22_ook_counter_value2 0x2D // R/W
|
||||
|
||||
#define RFM22_slicer_peak_hold 0x2E // R/W
|
||||
|
||||
#define RFM22_data_access_control 0x30 // R/W
|
||||
#define RFM22_dac_crc_ccitt 0x00 //
|
||||
#define RFM22_dac_crc_crc16 0x01 //
|
||||
#define RFM22_dac_crc_iec16 0x02 //
|
||||
#define RFM22_dac_crc_biacheva 0x03 //
|
||||
#define RFM22_dac_encrc 0x04 // CRC Enable. Cyclic Redundancy Check generation is enabled if this bit is set.
|
||||
#define RFM22_dac_enpactx 0x08 // Enable Packet TX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpactx = 1 will enable automatic packet handling in the TX path. Register 30–4D allow for various configurations of the packet structure. Setting enpactx = 0 will not do any packet handling in the TX path. It will only transmit what is loaded to the FIFO.
|
||||
#define RFM22_dac_skip2ph 0x10 // Skip 2nd Phase of Preamble Detection. If set, we skip the second phase of the preamble detection (under certain conditions) if antenna diversity is enabled.
|
||||
#define RFM22_dac_crcdonly 0x20 // CRC Data Only Enable. When this bit is set to 1 the CRC is calculated on and checked against the packet data fields only.
|
||||
#define RFM22_dac_lsbfrst 0x40 // LSB First Enable. The LSB of the data will be transmitted/received first if this bit is set.
|
||||
#define RFM22_dac_enpacrx 0x80 // Enable Packet RX Handling. If FIFO Mode (dtmod = 10) is being used automatic packet handling may be enabled. Setting enpacrx = 1 will enable automatic packet handling in the RX path. Register 30–4D allow for various configurations of the packet structure. Setting enpacrx = 0 will not do any packet handling in the RX path. It will only receive everything after the sync word and fill up the RX FIFO.
|
||||
|
||||
#define RFM22_ezmac_status 0x31 // R
|
||||
#define RFM22_ezmac_status_pksent 0x01 // Packet Sent. A 1 a packet has been sent by the radio. (Same bit as in register 03, but reading it does not reset the IRQ)
|
||||
#define RFM22_ezmac_status_pktx 0x02 // Packet Transmitting. When 1 the radio is currently transmitting a packet.
|
||||
#define RFM22_ezmac_status_crcerror 0x04 // CRC Error. When 1 a Cyclic Redundancy Check error has been detected. (Same bit as in register 03, but reading it does not reset the IRQ)
|
||||
#define RFM22_ezmac_status_pkvalid 0x08 // Valid Packet Received. When a 1 a valid packet has been received by the receiver. (Same bit as in register 03, but reading it does not reset the IRQ)
|
||||
#define RFM22_ezmac_status_pkrx 0x10 // Packet Receiving. When 1 the radio is currently receiving a valid packet.
|
||||
#define RFM22_ezmac_status_pksrch 0x20 // Packet Searching. When 1 the radio is searching for a valid packet.
|
||||
#define RFM22_ezmac_status_rxcrc1 0x40 // If high, it indicates the last CRC received is all one’s. May indicated Transmitter underflow in case of CRC error.
|
||||
|
||||
#define RFM22_header_control1 0x32 // R/W
|
||||
#define RFM22_header_cntl1_bcen_none 0x00 // No broadcast address enable.
|
||||
#define RFM22_header_cntl1_bcen_0 0x10 // Broadcast address enable for header byte 0.
|
||||
#define RFM22_header_cntl1_bcen_1 0x20 // Broadcast address enable for header byte 1.
|
||||
#define RFM22_header_cntl1_bcen_2 0x40 // Broadcast address enable for header byte 2.
|
||||
#define RFM22_header_cntl1_bcen_3 0x80 // Broadcast address enable for header byte 3.
|
||||
#define RFM22_header_cntl1_hdch_none 0x00 // No Received Header check
|
||||
#define RFM22_header_cntl1_hdch_0 0x01 // Received Header check for byte 0.
|
||||
#define RFM22_header_cntl1_hdch_1 0x02 // Received Header check for byte 1.
|
||||
#define RFM22_header_cntl1_hdch_2 0x04 // Received Header check for byte 2.
|
||||
#define RFM22_header_cntl1_hdch_3 0x08 // Received Header check for byte 3.
|
||||
|
||||
#define RFM22_header_control2 0x33 // R/W
|
||||
#define RFM22_header_cntl2_prealen 0x01 // MSB of Preamble Length. See register Preamble Length.
|
||||
#define RFM22_header_cntl2_synclen_3 0x00 // Synchronization Word 3
|
||||
#define RFM22_header_cntl2_synclen_32 0x02 // Synchronization Word 3 followed by 2
|
||||
#define RFM22_header_cntl2_synclen_321 0x04 // Synchronization Word 3 followed by 2 followed by 1
|
||||
#define RFM22_header_cntl2_synclen_3210 0x06 // Synchronization Word 3 followed by 2 followed by 1 followed by 0
|
||||
#define RFM22_header_cntl2_fixpklen 0x08 // Fix Packet Length. When fixpklen = 1 the packet length (pklen[7:0]) is not included in the header. When fixpklen = 0 the packet length is included in the header.
|
||||
#define RFM22_header_cntl2_hdlen_none 0x00 // no header
|
||||
#define RFM22_header_cntl2_hdlen_3 0x10 // header 3
|
||||
#define RFM22_header_cntl2_hdlen_32 0x20 // header 3 and 2
|
||||
#define RFM22_header_cntl2_hdlen_321 0x30 // header 3 and 2 and 1
|
||||
#define RFM22_header_cntl2_hdlen_3210 0x40 // header 3 and 2 and 1 and 0
|
||||
#define RFM22_header_cntl2_skipsyn 0x80 // If high, the system will ignore the syncword search timeout reset. The chip will not return to searching for Preamble, but instead will remain searching for Sync word.
|
||||
|
||||
#define RFM22_preamble_length 0x34 // R/W
|
||||
|
||||
#define RFM22_preamble_detection_ctrl1 0x35 // R/W
|
||||
#define RFM22_pre_det_ctrl1_preath_mask 0xF8 // Number of nibbles processed during detection.
|
||||
#define RFM22_pre_det_ctrl1_rssi_offset_mask 0x07 // Value added as offset to RSSI calculation. Every increment in this register results in an increment of +4 dB in the RSSI.
|
||||
|
||||
#define RFM22_sync_word3 0x36 // R/W
|
||||
#define RFM22_sync_word2 0x37 // R/W
|
||||
#define RFM22_sync_word1 0x38 // R/W
|
||||
#define RFM22_sync_word0 0x39 // R/W
|
||||
|
||||
#define RFM22_transmit_header3 0x3A // R/W
|
||||
#define RFM22_transmit_header2 0x3B // R/W
|
||||
#define RFM22_transmit_header1 0x3C // R/W
|
||||
#define RFM22_transmit_header0 0x3D // R/W
|
||||
|
||||
#define RFM22_transmit_packet_length 0x3E // R/W
|
||||
|
||||
#define RFM22_check_header3 0x3F // R/W
|
||||
#define RFM22_check_header2 0x40 // R/W
|
||||
#define RFM22_check_header1 0x41 // R/W
|
||||
#define RFM22_check_header0 0x42 // R/W
|
||||
|
||||
#define RFM22_header_enable3 0x43 // R/W
|
||||
#define RFM22_header_enable2 0x44 // R/W
|
||||
#define RFM22_header_enable1 0x45 // R/W
|
||||
#define RFM22_header_enable0 0x46 // R/W
|
||||
|
||||
#define RFM22_received_header3 0x47 // R
|
||||
#define RFM22_received_header2 0x48 // R
|
||||
#define RFM22_received_header1 0x49 // R
|
||||
#define RFM22_received_header0 0x4A // R
|
||||
|
||||
#define RFM22_received_packet_length 0x4B // R
|
||||
|
||||
#define RFM22_adc8_control 0x4F // R/W
|
||||
/*
|
||||
#define RFM22_analog_test_bus 0x50 // R/W
|
||||
#define RFM22_digital_test_bus 0x51 // R/W
|
||||
#define RFM22_tx_ramp_control 0x52 // R/W
|
||||
#define RFM22_pll_tune_time 0x53 // R/W
|
||||
|
||||
#define RFM22_calibration_control 0x55 // R/W
|
||||
|
||||
#define RFM22_modem_test 0x56 // R/W
|
||||
|
||||
#define RFM22_chargepump_test 0x57 // R/W
|
||||
#define RFM22_chargepump_current_trimming_override 0x58 // R/W
|
||||
|
||||
#define RFM22_divider_current_trimming 0x59 // R/W
|
||||
|
||||
#define RFM22_vco_current_trimming 0x5A // R/W
|
||||
#define RFM22_vco_calibration_override 0x5B // R/W
|
||||
|
||||
#define RFM22_synthersizer_test 0x5C // R/W
|
||||
|
||||
#define RFM22_block_enable_override1 0x5D // R/W
|
||||
#define RFM22_block_enable_override2 0x5E // R/W
|
||||
#define RFM22_block_enable_override3 0x5F // R/W
|
||||
*/
|
||||
#define RFM22_channel_filter_coeff_addr 0x60 // R/W
|
||||
#define RFM22_ch_fil_coeff_ad_inv_pre_th_mask 0xF0 //
|
||||
#define RFM22_ch_fil_coeff_ad_chfiladd_mask 0x0F // Channel Filter Coefficient Look-up Table Address. The address for channel filter coefficients used in the RX path.
|
||||
|
||||
|
||||
//#define RFM22_channel_filter_coeff_value 0x61 // R/W
|
||||
|
||||
#define RFM22_xtal_osc_por_ctrl 0x62 // R/W
|
||||
#define RFM22_xtal_osc_por_ctrl_pwst_mask 0xE0 // Internal Power States of the Chip.
|
||||
#define RFM22_xtal_osc_por_ctrl_clkhyst 0x10 // Clock Hysteresis Setting.
|
||||
#define RFM22_xtal_osc_por_ctrl_enbias2x 0x08 // 2 Times Higher Bias Current Enable.
|
||||
#define RFM22_xtal_osc_por_ctrl_enamp2x 0x04 // 2 Times Higher Amplification Enable.
|
||||
#define RFM22_xtal_osc_por_ctrl_bufovr 0x02 // Output Buffer Enable Override.
|
||||
#define RFM22_xtal_osc_por_ctrl_enbuf 0x01 // Output Buffer Enable.
|
||||
/*
|
||||
#define RFM22_rc_osc_coarse_calbration_override 0x63 // R/W
|
||||
#define RFM22_rc_osc_fine_calbration_override 0x64 // R/W
|
||||
|
||||
#define RFM22_ldo_control_override 0x65 // R/W
|
||||
#define RFM22_ldo_level_setting 0x66 // R/W
|
||||
|
||||
#define RFM22_deltasigma_adc_tuning1 0x67 // R/W
|
||||
#define RFM22_deltasigma_adc_tuning2 0x68 // R/W
|
||||
*/
|
||||
#define RFM22_agc_override1 0x69 // R/W
|
||||
#define RFM22_agc_ovr1_sgi 0x40 // AGC Loop, Set Gain Increase. If set to 0 then gain increasing will not be allowed. If set to 1 then gain increasing is allowed, default is 0.
|
||||
#define RFM22_agc_ovr1_agcen 0x20 // Automatic Gain Control Enable. When this bit is set then the result of the control can be read out from bits [4:0], otherwise the gain can be controlled manually by writing into bits [4:0].
|
||||
#define RFM22_agc_ovr1_lnagain 0x10 // LNA Gain Select. 0 = min gain = 5dB, 1 = max gain = 25 dB.
|
||||
#define RFM22_agc_ovr1_pga_mask 0x0F // PGA Gain Override Value.
|
||||
|
||||
//#define RFM22_agc_override2 0x6A // R/W
|
||||
|
||||
//#define RFM22_gfsk_fir_coeff_addr 0x6B // R/W
|
||||
//#define RFM22_gfsk_fir_coeff_value 0x6C // R/W
|
||||
|
||||
#define RFM22_tx_power 0x6D // R/W
|
||||
#define RFM22_tx_pwr_txpow_0 0x00 // +1dBm .. 1.25mW
|
||||
#define RFM22_tx_pwr_txpow_1 0x01 // +2dBm .. 1.6mW
|
||||
#define RFM22_tx_pwr_txpow_2 0x02 // +5dBm .. 3.16mW
|
||||
#define RFM22_tx_pwr_txpow_3 0x03 // +8dBm .. 6.3mW
|
||||
#define RFM22_tx_pwr_txpow_4 0x04 // +11dBm .. 12.6mW
|
||||
#define RFM22_tx_pwr_txpow_5 0x05 // +14dBm .. 25mW
|
||||
#define RFM22_tx_pwr_txpow_6 0x06 // +17dBm .. 50mW
|
||||
#define RFM22_tx_pwr_txpow_7 0x07 // +20dBm .. 100mW
|
||||
#define RFM22_tx_pwr_lna_sw 0x08 // LNA Switch Controller. If set, lna_sw control from the digital will go high during TX modes, and low during other times. If reset, the digital control signal is low at all times.
|
||||
#define RFM22_tx_pwr_papeaklvl_0 0x10 // " "
|
||||
#define RFM22_tx_pwr_papeaklvl_1 0x20 // PA Peak Detect Level (direct from register). 00 = 6.5, 01 = 7, 10 = 7.5, 11 = 8, 00 = default
|
||||
#define RFM22_tx_pwr_papeaken 0x40 // PA Peak Detector Enable.
|
||||
#define RFM22_tx_pwr_papeakval 0x80 // PA Peak Detector Value Read Register. Reading a 1 in this register when the papeaken=1 then the PA drain voltage is too high and the match network needs adjusting for optimal efficiency.
|
||||
|
||||
#define RFM22_tx_data_rate1 0x6E // R/W
|
||||
#define RFM22_tx_data_rate0 0x6F // R/W
|
||||
|
||||
#define RFM22_modulation_mode_control1 0x70 // R/W
|
||||
#define RFM22_mmc1_enwhite 0x01 // Data Whitening is Enabled if this bit is set.
|
||||
#define RFM22_mmc1_enmanch 0x02 // Manchester Coding is Enabled if this bit is set.
|
||||
#define RFM22_mmc1_enmaninv 0x04 // Manchester Data Inversion is Enabled if this bit is set.
|
||||
#define RFM22_mmc1_manppol 0x08 // Manchester Preamble Polarity (will transmit a series of 1 if set, or series of 0 if reset).
|
||||
#define RFM22_mmc1_enphpwdn 0x10 // If set, the Packet Handler will be powered down when chip is in low power mode.
|
||||
#define RFM22_mmc1_txdtrtscale 0x20 // This bit should be set for Data Rates below 30 kbps.
|
||||
|
||||
#define RFM22_modulation_mode_control2 0x71 // R/W
|
||||
#define RFM22_mmc2_modtyp_mask 0x03 // Modulation type.
|
||||
#define RFM22_mmc2_modtyp_none 0x00 //
|
||||
#define RFM22_mmc2_modtyp_ook 0x01 //
|
||||
#define RFM22_mmc2_modtyp_fsk 0x02 //
|
||||
#define RFM22_mmc2_modtyp_gfsk 0x03 //
|
||||
#define RFM22_mmc2_fd 0x04 // MSB of Frequency Deviation Setting, see "Register 72h. Frequency Deviation".
|
||||
#define RFM22_mmc2_eninv 0x08 // Invert TX and RX Data.
|
||||
#define RFM22_mmc2_dtmod_mask 0x30 // Modulation source.
|
||||
#define RFM22_mmc2_dtmod_dm_gpio 0x00 //
|
||||
#define RFM22_mmc2_dtmod_dm_sdi 0x10 //
|
||||
#define RFM22_mmc2_dtmod_fifo 0x20 //
|
||||
#define RFM22_mmc2_dtmod_pn9 0x30 //
|
||||
#define RFM22_mmc2_trclk_mask 0xC0 // TX Data Clock Configuration.
|
||||
#define RFM22_mmc2_trclk_clk_none 0x00 //
|
||||
#define RFM22_mmc2_trclk_clk_gpio 0x40 //
|
||||
#define RFM22_mmc2_trclk_clk_sdo 0x80 //
|
||||
#define RFM22_mmc2_trclk_clk_nirq 0xC0 //
|
||||
|
||||
#define RFM22_frequency_deviation 0x72 // R/W
|
||||
|
||||
#define RFM22_frequency_offset1 0x73 // R/W
|
||||
#define RFM22_frequency_offset2 0x74 // R/W
|
||||
|
||||
#define RFM22_frequency_band_select 0x75 // R/W
|
||||
#define RFM22_fb_mask 0x1F
|
||||
#define RFM22_fbs_hbsel 0x20
|
||||
#define RFM22_fbs_sbse 0x40
|
||||
|
||||
#define RFM22_nominal_carrier_frequency1 0x76 // R/W
|
||||
#define RFM22_nominal_carrier_frequency0 0x77 // R/W
|
||||
|
||||
#define RFM22_frequency_hopping_channel_select 0x79 // R/W
|
||||
#define RFM22_frequency_hopping_step_size 0x7A // R/W
|
||||
|
||||
#define RFM22_tx_fifo_control1 0x7C // R/W .. TX FIFO Almost Full Threshold (0 - 63)
|
||||
#define RFM22_tx_fifo_control1_mask 0x3F
|
||||
|
||||
#define RFM22_tx_fifo_control2 0x7D // R/W .. TX FIFO Almost Empty Threshold (0 - 63)
|
||||
#define RFM22_tx_fifo_control2_mask 0x3F
|
||||
|
||||
#define RFM22_rx_fifo_control 0x7E // R/W .. RX FIFO Almost Full Threshold (0 - 63)
|
||||
#define RFM22_rx_fifo_control_mask 0x3F
|
||||
|
||||
#define RFM22_fifo_access 0x7F // R/W
|
||||
|
||||
// ************************************
|
||||
|
||||
typedef int16_t ( *t_rfm22_TxDataByteCallback ) (void);
|
||||
typedef bool ( *t_rfm22_RxDataCallback ) (void *data, uint8_t len);
|
||||
|
||||
// ************************************
|
||||
|
||||
uint32_t rfm22_minFrequency(void);
|
||||
uint32_t rfm22_maxFrequency(void);
|
||||
|
||||
void rfm22_setNominalCarrierFrequency(uint32_t frequency_hz);
|
||||
uint32_t rfm22_getNominalCarrierFrequency(void);
|
||||
|
||||
float rfm22_getFrequencyStepSize(void);
|
||||
|
||||
void rfm22_setFreqHopChannel(uint8_t channel);
|
||||
uint8_t rfm22_freqHopChannel(void);
|
||||
|
||||
uint32_t rfm22_freqHopSize(void);
|
||||
|
||||
void rfm22_setDatarate(uint32_t datarate_bps, bool data_whitening);
|
||||
uint32_t rfm22_getDatarate(void);
|
||||
|
||||
void rfm22_setRxMode(uint8_t mode, bool multi_packet_mode);
|
||||
|
||||
int8_t rfm22_getRSSI(void);
|
||||
|
||||
int8_t rfm22_receivedRSSI(void);
|
||||
int32_t rfm22_receivedAFCHz(void);
|
||||
uint16_t rfm22_receivedLength(void);
|
||||
uint8_t * rfm22_receivedPointer(void);
|
||||
void rfm22_receivedDone(void);
|
||||
|
||||
int32_t rfm22_sendData(void *data, uint16_t length, bool send_immediately);
|
||||
|
||||
void rfm22_setFreqCalibration(uint8_t value);
|
||||
uint8_t rfm22_getFreqCalibration(void);
|
||||
|
||||
void rfm22_setTxPower(uint8_t tx_pwr);
|
||||
uint8_t rfm22_getTxPower(void);
|
||||
|
||||
void rfm22_setTxStream(void); // TEST ONLY
|
||||
|
||||
void rfm22_setTxNormal(void);
|
||||
void rfm22_setTxCarrierMode(void);
|
||||
void rfm22_setTxPNMode(void);
|
||||
|
||||
int8_t rfm22_currentMode(void);
|
||||
bool rfm22_transmitting(void);
|
||||
|
||||
bool rfm22_channelIsClear(void);
|
||||
|
||||
bool rfm22_txReady(void);
|
||||
|
||||
void rfm22_1ms_tick(void);
|
||||
|
||||
void rfm22_TxDataByte_SetCallback(t_rfm22_TxDataByteCallback new_function);
|
||||
void rfm22_RxData_SetCallback(t_rfm22_RxDataCallback new_function);
|
||||
|
||||
int rfm22_init_scan_spectrum(uint32_t min_frequency_hz, uint32_t max_frequency_hz);
|
||||
int rfm22_init_tx_stream(uint32_t min_frequency_hz, uint32_t max_frequency_hz);
|
||||
int rfm22_init_rx_stream(uint32_t min_frequency_hz, uint32_t max_frequency_hz);
|
||||
int rfm22_init_normal(uint32_t id, uint32_t min_frequency_hz, uint32_t max_frequency_hz, uint32_t freq_hop_step_size);
|
||||
|
||||
#endif /* PIOS_RFM22B_PRIV_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
@ -1,38 +1,38 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_USB_UTIL USB utility functions
|
||||
* @brief USB utility functions
|
||||
* @{
|
||||
*
|
||||
* @file pios_usb_util.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief USB utility functions
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_USB_UTIL_H
|
||||
#define PIOS_USB_UTIL_H
|
||||
|
||||
#include <stdint.h> /* uint8_t */
|
||||
|
||||
uint8_t * PIOS_USB_UTIL_AsciiToUtf8(uint8_t * dst, uint8_t * src, uint16_t srclen);
|
||||
|
||||
#endif /* PIOS_USB_UTIL_H */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_USB_UTIL USB utility functions
|
||||
* @brief USB utility functions
|
||||
* @{
|
||||
*
|
||||
* @file pios_usb_util.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief USB utility functions
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_USB_UTIL_H
|
||||
#define PIOS_USB_UTIL_H
|
||||
|
||||
#include <stdint.h> /* uint8_t */
|
||||
|
||||
uint8_t * PIOS_USB_UTIL_AsciiToUtf8(uint8_t * dst, uint8_t * src, uint16_t srclen);
|
||||
|
||||
#endif /* PIOS_USB_UTIL_H */
|
||||
|
12
flight/RemoteSystemsTempFiles/.project
Normal file
12
flight/RemoteSystemsTempFiles/.project
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>RemoteSystemsTempFiles</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.rse.ui.remoteSystemsTempNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -1,53 +1,53 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup OpenPilotSystem OpenPilot System
|
||||
* @{
|
||||
* @addtogroup OpenPilotCore OpenPilot Core
|
||||
* @{
|
||||
* @file openpilot.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief Main OpenPilot header.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef OPENPILOT_H
|
||||
#define OPENPILOT_H
|
||||
|
||||
|
||||
/* PIOS Includes */
|
||||
#include <pios.h>
|
||||
|
||||
/* OpenPilot Libraries */
|
||||
#include "op_config.h"
|
||||
#include "utlist.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "eventdispatcher.h"
|
||||
#include "alarms.h"
|
||||
#include "taskmonitor.h"
|
||||
#include "uavtalk.h"
|
||||
|
||||
/* Global Functions */
|
||||
void OpenPilotInit(void);
|
||||
|
||||
#endif /* OPENPILOT_H */
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @addtogroup OpenPilotSystem OpenPilot System
|
||||
* @{
|
||||
* @addtogroup OpenPilotCore OpenPilot Core
|
||||
* @{
|
||||
* @file openpilot.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief Main OpenPilot header.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef OPENPILOT_H
|
||||
#define OPENPILOT_H
|
||||
|
||||
|
||||
/* PIOS Includes */
|
||||
#include <pios.h>
|
||||
|
||||
/* OpenPilot Libraries */
|
||||
#include "op_config.h"
|
||||
#include "utlist.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "eventdispatcher.h"
|
||||
#include "alarms.h"
|
||||
#include "taskmonitor.h"
|
||||
#include "uavtalk.h"
|
||||
|
||||
/* Global Functions */
|
||||
void OpenPilotInit(void);
|
||||
|
||||
#endif /* OPENPILOT_H */
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>796</width>
|
||||
<height>605</height>
|
||||
<width>730</width>
|
||||
<height>602</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -1359,7 +1359,7 @@ margin:1px;</string>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ConfigccpmWidget" name="widget_3" native="true"/>
|
||||
<widget class="ConfigCcpmWidget" name="widget_3" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
@ -2893,7 +2893,7 @@ p, li { white-space: pre-wrap; }
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigccpmWidget</class>
|
||||
<class>ConfigCcpmWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>cfg_vehicletypes/configccpmwidget.h</header>
|
||||
<container>1</container>
|
||||
@ -2999,22 +2999,6 @@ p, li { white-space: pre-wrap; }
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mrPitchMixLevel</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>mrPitchMixValue</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>83</x>
|
||||
<y>228</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>82</x>
|
||||
<y>168</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mrRollMixLevel</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
@ -3047,5 +3031,21 @@ p, li { white-space: pre-wrap; }
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mrPitchMixLevel</sender>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>mrPitchMixValue</receiver>
|
||||
<slot>setNum(int)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>92</x>
|
||||
<y>222</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>92</x>
|
||||
<y>151</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
@ -3959,7 +3959,7 @@ margin:1px;</string>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>ccpmCollectiveSlider</sender>
|
||||
<signal>sliderMoved(int)</signal>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ccpmCollectivespinBox</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
@ -4007,7 +4007,7 @@ margin:1px;</string>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>ccpmRevoSlider</sender>
|
||||
<signal>sliderMoved(int)</signal>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ccpmREVOspinBox</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
@ -4023,7 +4023,7 @@ margin:1px;</string>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>SwashLvlPositionSlider</sender>
|
||||
<signal>sliderMoved(int)</signal>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>SwashLvlPositionSpinBox</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
@ -4071,7 +4071,7 @@ margin:1px;</string>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>ccpmCollectiveScale</sender>
|
||||
<signal>sliderMoved(int)</signal>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ccpmCollectiveScaleBox</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
@ -4087,7 +4087,7 @@ margin:1px;</string>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>ccpmCyclicScale</sender>
|
||||
<signal>sliderMoved(int)</signal>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ccpmCyclicScaleBox</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
@ -4119,7 +4119,7 @@ margin:1px;</string>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>ccpmPitchScale</sender>
|
||||
<signal>sliderMoved(int)</signal>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ccpmPitchScaleBox</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
@ -4167,7 +4167,7 @@ margin:1px;</string>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>ccpmRollScale</sender>
|
||||
<signal>sliderMoved(int)</signal>
|
||||
<signal>valueChanged(int)</signal>
|
||||
<receiver>ccpmRollScaleBox</receiver>
|
||||
<slot>setValue(int)</slot>
|
||||
<hints>
|
||||
|
@ -25,7 +25,7 @@
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "configccpmwidget.h"
|
||||
#include "mixersettings.h"
|
||||
//#include "mixersettings.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
@ -44,21 +44,17 @@
|
||||
#define Pi 3.14159265358979323846
|
||||
|
||||
|
||||
ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
ConfigCcpmWidget::ConfigCcpmWidget(QWidget *parent) : VehicleConfig(parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
m_ccpm = new Ui_ccpmWidget();
|
||||
m_ccpm->setupUi(this);
|
||||
SwashLvlConfigurationInProgress=0;
|
||||
SwashLvlState=0;
|
||||
SwashLvlServoInterlock=0;
|
||||
updatingFromHardware=FALSE;
|
||||
updatingToHardware=FALSE;
|
||||
|
||||
// Now connect the widget to the ManualControlCommand / Channel UAVObject
|
||||
//ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
//UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
m_ccpm = new Ui_ccpmWidget();
|
||||
m_ccpm->setupUi(this);
|
||||
|
||||
// Initialization of the swashplaye widget
|
||||
m_ccpm->SwashplateImage->setScene(new QGraphicsScene(this));
|
||||
@ -147,21 +143,18 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
UAVObjectField * curve2source = mixerSettings->getField("Curve2Source");
|
||||
Q_ASSERT(curve2source);
|
||||
|
||||
QStringList channels;
|
||||
channels << "Channel1" << "Channel2" << "Channel3" << "Channel4" <<
|
||||
"Channel5" << "Channel6" << "Channel7" << "Channel8" << "None";
|
||||
m_ccpm->ccpmEngineChannel->addItems(channels);
|
||||
m_ccpm->ccpmEngineChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmTailChannel->addItems(channels);
|
||||
m_ccpm->ccpmTailChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoWChannel->addItems(channels);
|
||||
m_ccpm->ccpmServoWChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoXChannel->addItems(channels);
|
||||
m_ccpm->ccpmServoXChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoYChannel->addItems(channels);
|
||||
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoZChannel->addItems(channels);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmEngineChannel->addItems(channelNames);
|
||||
m_ccpm->ccpmEngineChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmTailChannel->addItems(channelNames);
|
||||
m_ccpm->ccpmTailChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoWChannel->addItems(channelNames);
|
||||
m_ccpm->ccpmServoWChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoXChannel->addItems(channelNames);
|
||||
m_ccpm->ccpmServoXChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoYChannel->addItems(channelNames);
|
||||
m_ccpm->ccpmServoYChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoZChannel->addItems(channelNames);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(0);
|
||||
|
||||
QStringList Types;
|
||||
Types << QString::fromUtf8("CCPM 2 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 90º") <<
|
||||
@ -170,12 +163,14 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
QString::fromUtf8("Custom - User Angles") << QString::fromUtf8("Custom - Advanced Settings");
|
||||
m_ccpm->ccpmType->addItems(Types);
|
||||
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - 1);
|
||||
requestccpmUpdate();
|
||||
|
||||
UpdateCurveSettings();
|
||||
|
||||
//disable changing number of points in curves until UAVObjects have more than 5
|
||||
m_ccpm->NumCurvePoints->setEnabled(0);
|
||||
|
||||
refreshWidgetsValues(QString("HeliCP"));
|
||||
|
||||
UpdateType();
|
||||
|
||||
//connect(m_ccpm->saveccpmToSD, SIGNAL(clicked()), this, SLOT(saveccpmUpdate()));
|
||||
@ -205,9 +200,6 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
connect(m_ccpm->CurveSettings, SIGNAL(cellChanged (int, int)), this, SLOT(UpdateCurveWidgets()));
|
||||
connect(m_ccpm->TabObject, SIGNAL(currentChanged ( QWidget * )), this, SLOT(UpdateType()));
|
||||
|
||||
// connect(m_ccpm->SwashLvlSwashplateImage, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateRedraw()));
|
||||
|
||||
|
||||
connect(m_ccpm->PitchCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updatePitchCurveValue(QList<double>,double)));
|
||||
connect(m_ccpm->ThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateThrottleCurveValue(QList<double>,double)));
|
||||
|
||||
@ -216,6 +208,7 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
connect(m_ccpm->SwashLvlCancelButton, SIGNAL(clicked()), this, SLOT(SwashLvlCancelButtonPressed()));
|
||||
connect(m_ccpm->SwashLvlFinishButton, SIGNAL(clicked()), this, SLOT(SwashLvlFinishButtonPressed()));
|
||||
|
||||
connect(m_ccpm->ccpmCollectivePassthrough, SIGNAL(clicked()),this, SLOT(SetUIComponentVisibilities()));
|
||||
connect(m_ccpm->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
|
||||
connect(m_ccpm->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
|
||||
|
||||
@ -224,18 +217,96 @@ ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
ccpmSwashplateRedraw();
|
||||
}
|
||||
|
||||
ConfigccpmWidget::~ConfigccpmWidget()
|
||||
ConfigCcpmWidget::~ConfigCcpmWidget()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::UpdateType()
|
||||
void ConfigCcpmWidget::setupUI(QString frameType)
|
||||
{
|
||||
}
|
||||
|
||||
void ConfigCcpmWidget::ResetActuators(GUIConfigDataUnion* configData)
|
||||
{
|
||||
configData->heli.Throttle = 0;
|
||||
configData->heli.Tail = 0;
|
||||
configData->heli.ServoIndexW = 0;
|
||||
configData->heli.ServoIndexX = 0;
|
||||
configData->heli.ServoIndexY = 0;
|
||||
configData->heli.ServoIndexZ = 0;
|
||||
}
|
||||
|
||||
QStringList ConfigCcpmWidget::getChannelDescriptions()
|
||||
{
|
||||
int i;
|
||||
QStringList channelDesc;
|
||||
|
||||
// init a channel_numelem list of channel desc defaults
|
||||
for (i=0; i < (int)(ConfigCcpmWidget::CHANNEL_NUMELEM); i++)
|
||||
{
|
||||
channelDesc.append(QString("-"));
|
||||
}
|
||||
|
||||
// get the gui config data
|
||||
GUIConfigDataUnion configData = GetConfigData();
|
||||
heliGUISettingsStruct heli = configData.heli;
|
||||
|
||||
if (heli.Throttle > 0)
|
||||
channelDesc[heli.Throttle - 1] = QString("Throttle");
|
||||
if (heli.Tail > 0)
|
||||
channelDesc[heli.Tail - 1] = QString("Tail");
|
||||
|
||||
switch(heli.FirstServoIndex)
|
||||
{
|
||||
case 0: //front
|
||||
if (heli.ServoIndexW > 0)
|
||||
channelDesc[heli.ServoIndexW - 1] = QString("Elevator");
|
||||
if (heli.ServoIndexX > 0)
|
||||
channelDesc[heli.ServoIndexX - 1] = QString("Roll1");
|
||||
if (heli.ServoIndexY > 0)
|
||||
channelDesc[heli.ServoIndexY - 1] = QString("Roll2");
|
||||
break;
|
||||
|
||||
case 1: //right
|
||||
if (heli.ServoIndexW > 0)
|
||||
channelDesc[heli.ServoIndexW - 1] = QString("ServoW");
|
||||
if (heli.ServoIndexX > 0)
|
||||
channelDesc[heli.ServoIndexX - 1] = QString("ServoX");
|
||||
if (heli.ServoIndexY > 0)
|
||||
channelDesc[heli.ServoIndexY - 1] = QString("ServoY");
|
||||
break;
|
||||
|
||||
case 2: //rear
|
||||
if (heli.ServoIndexW > 0)
|
||||
channelDesc[heli.ServoIndexW - 1] = QString("Elevator");
|
||||
if (heli.ServoIndexX > 0)
|
||||
channelDesc[heli.ServoIndexX - 1] = QString("Roll1");
|
||||
if (heli.ServoIndexY > 0)
|
||||
channelDesc[heli.ServoIndexY - 1] = QString("Roll2");
|
||||
break;
|
||||
|
||||
case 3: //left
|
||||
if (heli.ServoIndexW > 0)
|
||||
channelDesc[heli.ServoIndexW - 1] = QString("ServoW");
|
||||
if (heli.ServoIndexX > 0)
|
||||
channelDesc[heli.ServoIndexX - 1] = QString("ServoX");
|
||||
if (heli.ServoIndexY > 0)
|
||||
channelDesc[heli.ServoIndexY - 1] = QString("ServoY");
|
||||
break;
|
||||
|
||||
}
|
||||
if (heli.ServoIndexZ > 0)
|
||||
channelDesc[heli.ServoIndexZ - 1] = QString("ServoZ");
|
||||
|
||||
return channelDesc;
|
||||
}
|
||||
|
||||
void ConfigCcpmWidget::UpdateType()
|
||||
{
|
||||
int TypeInt,SingleServoIndex,NumServosDefined;
|
||||
QString TypeText;
|
||||
double AdjustmentAngle=0;
|
||||
|
||||
UpdateCCPMOptionsFromUI();
|
||||
SetUIComponentVisibilities();
|
||||
|
||||
TypeInt = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
|
||||
@ -283,8 +354,8 @@ void ConfigccpmWidget::UpdateType()
|
||||
m_ccpm->ccpmAngleZ->setValue(0);
|
||||
m_ccpm->ccpmAngleY->setEnabled(0);
|
||||
m_ccpm->ccpmAngleZ->setEnabled(0);
|
||||
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoYChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoYChannel->setEnabled(0);
|
||||
m_ccpm->ccpmServoZChannel->setEnabled(0);
|
||||
//m_ccpm->ccpmCorrectionAngle->setValue(0);
|
||||
@ -298,7 +369,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360));
|
||||
m_ccpm->ccpmAngleZ->setValue(0);
|
||||
m_ccpm->ccpmAngleZ->setEnabled(0);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoZChannel->setEnabled(0);
|
||||
//m_ccpm->ccpmCorrectionAngle->setValue(0);
|
||||
NumServosDefined=3;
|
||||
@ -323,7 +394,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 240,360));
|
||||
m_ccpm->ccpmAngleZ->setValue(0);
|
||||
m_ccpm->ccpmAngleZ->setEnabled(0);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoZChannel->setEnabled(0);
|
||||
//m_ccpm->ccpmCorrectionAngle->setValue(0);
|
||||
NumServosDefined=3;
|
||||
@ -336,7 +407,7 @@ void ConfigccpmWidget::UpdateType()
|
||||
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 220,360));
|
||||
m_ccpm->ccpmAngleZ->setValue(0);
|
||||
m_ccpm->ccpmAngleZ->setEnabled(0);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoZChannel->setEnabled(0);
|
||||
//m_ccpm->ccpmCorrectionAngle->setValue(0);
|
||||
NumServosDefined=3;
|
||||
@ -350,8 +421,8 @@ void ConfigccpmWidget::UpdateType()
|
||||
m_ccpm->ccpmAngleZ->setValue(0);
|
||||
m_ccpm->ccpmAngleY->setEnabled(0);
|
||||
m_ccpm->ccpmAngleZ->setEnabled(0);
|
||||
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
|
||||
m_ccpm->ccpmServoYChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(0);
|
||||
m_ccpm->ccpmServoYChannel->setEnabled(0);
|
||||
m_ccpm->ccpmServoZChannel->setEnabled(0);
|
||||
//m_ccpm->ccpmCorrectionAngle->setValue(0);
|
||||
@ -407,12 +478,12 @@ void ConfigccpmWidget::UpdateType()
|
||||
/**
|
||||
Resets a mixer curve
|
||||
*/
|
||||
void ConfigccpmWidget::resetMixer(MixerCurveWidget *mixer, int numElements)
|
||||
void ConfigCcpmWidget::resetMixer(MixerCurveWidget *mixer, int numElements)
|
||||
{
|
||||
mixer->initLinearCurve(numElements,(double)1);
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::UpdateCurveWidgets()
|
||||
void ConfigCcpmWidget::UpdateCurveWidgets()
|
||||
{
|
||||
int NumCurvePoints,i,Changed;
|
||||
QList<double> curveValues;
|
||||
@ -446,7 +517,7 @@ void ConfigccpmWidget::UpdateCurveWidgets()
|
||||
if (Changed==1)m_ccpm->PitchCurve->setCurve(curveValues);
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::updatePitchCurveValue(QList<double> curveValues0,double Value0)
|
||||
void ConfigCcpmWidget::updatePitchCurveValue(QList<double> curveValues0,double Value0)
|
||||
{
|
||||
Q_UNUSED(curveValues0);
|
||||
Q_UNUSED(Value0);
|
||||
@ -470,7 +541,7 @@ void ConfigccpmWidget::updatePitchCurveValue(QList<double> curveValues0,double V
|
||||
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::updateThrottleCurveValue(QList<double> curveValues0,double Value0)
|
||||
void ConfigCcpmWidget::updateThrottleCurveValue(QList<double> curveValues0,double Value0)
|
||||
{
|
||||
Q_UNUSED(curveValues0);
|
||||
Q_UNUSED(Value0);
|
||||
@ -495,7 +566,7 @@ void ConfigccpmWidget::updateThrottleCurveValue(QList<double> curveValues0,doubl
|
||||
}
|
||||
|
||||
|
||||
void ConfigccpmWidget::UpdateCurveSettings()
|
||||
void ConfigCcpmWidget::UpdateCurveSettings()
|
||||
{
|
||||
int NumCurvePoints,i;
|
||||
double scale;
|
||||
@ -625,7 +696,7 @@ void ConfigccpmWidget::UpdateCurveSettings()
|
||||
UpdateCurveWidgets();
|
||||
|
||||
}
|
||||
void ConfigccpmWidget::GenerateCurve()
|
||||
void ConfigCcpmWidget::GenerateCurve()
|
||||
{
|
||||
int NumCurvePoints,CurveToGenerate,i;
|
||||
double value1, value2, value3, scale;
|
||||
@ -695,7 +766,7 @@ void ConfigccpmWidget::GenerateCurve()
|
||||
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::ccpmSwashplateRedraw()
|
||||
void ConfigCcpmWidget::ccpmSwashplateRedraw()
|
||||
{
|
||||
double angle[CCPM_MAX_SWASH_SERVOS],CorrectionAngle,x,y,w,h,radius,CenterX,CenterY;
|
||||
int used[CCPM_MAX_SWASH_SERVOS],defined[CCPM_MAX_SWASH_SERVOS],i;
|
||||
@ -735,10 +806,10 @@ void ConfigccpmWidget::ccpmSwashplateRedraw()
|
||||
defined[1]=(m_ccpm->ccpmServoXChannel->isEnabled());
|
||||
defined[2]=(m_ccpm->ccpmServoYChannel->isEnabled());
|
||||
defined[3]=(m_ccpm->ccpmServoZChannel->isEnabled());
|
||||
used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
|
||||
used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
|
||||
used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
|
||||
used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
|
||||
used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()>0)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
|
||||
used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()>0)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
|
||||
used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()>0)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
|
||||
used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()>0)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
|
||||
angle[0]=(CorrectionAngle+180+m_ccpm->ccpmAngleW->value())*Pi/180.00;
|
||||
angle[1]=(CorrectionAngle+180+m_ccpm->ccpmAngleX->value())*Pi/180.00;
|
||||
angle[2]=(CorrectionAngle+180+m_ccpm->ccpmAngleY->value())*Pi/180.00;
|
||||
@ -796,69 +867,14 @@ void ConfigccpmWidget::ccpmSwashplateRedraw()
|
||||
//m_ccpm->SwashplateImage->fitInView(SwashplateImg, Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::ccpmSwashplateUpdate()
|
||||
void ConfigCcpmWidget::ccpmSwashplateUpdate()
|
||||
{
|
||||
ccpmSwashplateRedraw();
|
||||
SetUIComponentVisibilities();
|
||||
UpdateMixer();
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::ccpmChannelCheck()
|
||||
{
|
||||
if((m_ccpm->ccpmServoWChannel->currentIndex()==8)&&(m_ccpm->ccpmServoWChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoWLabel->setText("<font color=red>Servo W</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoWLabel->setText("<font color=black>Servo W</font>");
|
||||
}
|
||||
if((m_ccpm->ccpmServoXChannel->currentIndex()==8)&&(m_ccpm->ccpmServoXChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoXLabel->setText("<font color=red>Servo X</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoXLabel->setText("<font color=black>Servo X</font>");
|
||||
}
|
||||
if((m_ccpm->ccpmServoYChannel->currentIndex()==8)&&(m_ccpm->ccpmServoYChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoYLabel->setText("<font color=red>Servo Y</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoYLabel->setText("<font color=black>Servo Y</font>");
|
||||
}
|
||||
if((m_ccpm->ccpmServoZChannel->currentIndex()==8)&&(m_ccpm->ccpmServoZChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoZLabel->setText("<font color=red>Servo Z</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoZLabel->setText("<font color=black>Servo Z</font>");
|
||||
}
|
||||
|
||||
if((m_ccpm->ccpmEngineChannel->currentIndex()==8)&&(m_ccpm->ccpmEngineChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmEngineLabel->setText("<font color=red>Engine</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmEngineLabel->setText("<font color=black>Engine</font>");
|
||||
}
|
||||
|
||||
if((m_ccpm->ccpmTailChannel->currentIndex()==8)&&(m_ccpm->ccpmTailChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmTailLabel->setText("<font color=red>Tail Rotor</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmTailLabel->setText("<font color=black>Tail Rotor</font>");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::UpdateMixer()
|
||||
void ConfigCcpmWidget::UpdateMixer()
|
||||
{
|
||||
bool useCCPM;
|
||||
bool useCyclic;
|
||||
@ -866,13 +882,14 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
float CollectiveConstant,PitchConstant,RollConstant,ThisAngle[6];
|
||||
QString Channel;
|
||||
|
||||
ccpmChannelCheck();
|
||||
UpdateCCPMOptionsFromUI();
|
||||
|
||||
useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
useCyclic = GUIConfigData.heli.ccpmLinkRollState;
|
||||
throwConfigError(QString("HeliCP"));
|
||||
|
||||
CollectiveConstant = (float)GUIConfigData.heli.SliderValue0 / 100.00;
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
|
||||
useCCPM = !(config.heli.ccpmCollectivePassthroughState || !config.heli.ccpmLinkCyclicState);
|
||||
useCyclic = config.heli.ccpmLinkRollState;
|
||||
|
||||
CollectiveConstant = (float)config.heli.SliderValue0 / 100.00;
|
||||
|
||||
if (useCCPM)
|
||||
{//cyclic = 1 - collective
|
||||
@ -881,18 +898,18 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
}
|
||||
else
|
||||
{
|
||||
PitchConstant = (float)GUIConfigData.heli.SliderValue1 / 100.00;;
|
||||
PitchConstant = (float)config.heli.SliderValue1 / 100.00;;
|
||||
if (useCyclic)
|
||||
{
|
||||
RollConstant = PitchConstant;
|
||||
}
|
||||
else
|
||||
{
|
||||
RollConstant = (float)GUIConfigData.heli.SliderValue2 / 100.00;;
|
||||
RollConstant = (float)config.heli.SliderValue2 / 100.00;;
|
||||
}
|
||||
}
|
||||
|
||||
if (GUIConfigData.heli.SwasplateType>0)
|
||||
if (config.heli.SwashplateType>0)
|
||||
{//not advanced settings
|
||||
//get the channel data from the ui
|
||||
MixerChannelData[0] = m_ccpm->ccpmEngineChannel->currentIndex();
|
||||
@ -914,18 +931,18 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
ThisEnable[4] = m_ccpm->ccpmServoYChannel->isEnabled();
|
||||
ThisEnable[5] = m_ccpm->ccpmServoZChannel->isEnabled();
|
||||
|
||||
ServosText[0]->setPlainText(QString("%1").arg( MixerChannelData[2]+1 ));
|
||||
ServosText[1]->setPlainText(QString("%1").arg( MixerChannelData[3]+1 ));
|
||||
ServosText[2]->setPlainText(QString("%1").arg( MixerChannelData[4]+1 ));
|
||||
ServosText[3]->setPlainText(QString("%1").arg( MixerChannelData[5]+1 ));
|
||||
ServosText[0]->setPlainText(QString("%1").arg( MixerChannelData[2] ));
|
||||
ServosText[1]->setPlainText(QString("%1").arg( MixerChannelData[3] ));
|
||||
ServosText[2]->setPlainText(QString("%1").arg( MixerChannelData[4] ));
|
||||
ServosText[3]->setPlainText(QString("%1").arg( MixerChannelData[5] ));
|
||||
|
||||
|
||||
//go through the user data and update the mixer matrix
|
||||
for (i=0;i<6;i++)
|
||||
{
|
||||
if ((MixerChannelData[i]<8)&&((ThisEnable[i])||(i<2)))
|
||||
if ((MixerChannelData[i]>0)&&((ThisEnable[i])||(i<2)))
|
||||
{
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->setText(QString("%1").arg( MixerChannelData[i]+1 ));
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->setText(QString("%1").arg( MixerChannelData[i] ));
|
||||
//config the vector
|
||||
if (i==0)
|
||||
{//motor-engine
|
||||
@ -947,8 +964,8 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
{//Swashplate
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg((int)(127.0*CollectiveConstant)));//ThrottleCurve2
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg((int)(127.0*(RollConstant)*sin((180+GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Roll
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg((int)(127.0*(PitchConstant)*cos((GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Pitch
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg((int)(127.0*(RollConstant)*sin((180+config.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Roll
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg((int)(127.0*(PitchConstant)*cos((config.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Pitch
|
||||
m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw
|
||||
|
||||
}
|
||||
@ -970,246 +987,167 @@ void ConfigccpmWidget::UpdateMixer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**************************
|
||||
* ccpm settings
|
||||
**************************/
|
||||
/*
|
||||
Get the state of the UI check boxes and change the visibility of sliders
|
||||
typedef struct {
|
||||
uint SwasplateType:3;
|
||||
uint FirstServoIndex:2;
|
||||
uint CorrectionAngle:9;
|
||||
uint ccpmCollectivePassthroughState:1;
|
||||
uint ccpmLinkCyclicState:1;
|
||||
uint ccpmLinkRollState:1;
|
||||
uint CollectiveChannel:3;
|
||||
uint padding:12;
|
||||
} __attribute__((packed)) heliGUISettingsStruct;
|
||||
|
||||
*/
|
||||
void ConfigccpmWidget::UpdateCCPMOptionsFromUI()
|
||||
QString ConfigCcpmWidget::updateConfigObjects()
|
||||
{
|
||||
QString airframeType = "HeliCP";
|
||||
|
||||
bool useCCPM;
|
||||
bool useCyclic;
|
||||
|
||||
if (updatingFromHardware) return;
|
||||
|
||||
if (updatingFromHardware == TRUE) return airframeType;
|
||||
|
||||
updatingFromHardware = TRUE;
|
||||
|
||||
//get the user options
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
|
||||
//swashplate config
|
||||
GUIConfigData.heli.SwasplateType = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
|
||||
GUIConfigData.heli.FirstServoIndex = m_ccpm->ccpmSingleServo->currentIndex();
|
||||
|
||||
config.heli.SwashplateType = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
|
||||
config.heli.FirstServoIndex = m_ccpm->ccpmSingleServo->currentIndex();
|
||||
|
||||
//ccpm mixing options
|
||||
GUIConfigData.heli.ccpmCollectivePassthroughState = m_ccpm->ccpmCollectivePassthrough->isChecked();
|
||||
GUIConfigData.heli.ccpmLinkCyclicState = m_ccpm->ccpmLinkCyclic->isChecked();
|
||||
GUIConfigData.heli.ccpmLinkRollState = m_ccpm->ccpmLinkRoll->isChecked();
|
||||
useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
useCyclic = GUIConfigData.heli.ccpmLinkRollState;
|
||||
|
||||
config.heli.ccpmCollectivePassthroughState = m_ccpm->ccpmCollectivePassthrough->isChecked();
|
||||
config.heli.ccpmLinkCyclicState = m_ccpm->ccpmLinkCyclic->isChecked();
|
||||
config.heli.ccpmLinkRollState = m_ccpm->ccpmLinkRoll->isChecked();
|
||||
useCCPM = !(config.heli.ccpmCollectivePassthroughState || !config.heli.ccpmLinkCyclicState);
|
||||
useCyclic = config.heli.ccpmLinkRollState;
|
||||
|
||||
//correction angle
|
||||
GUIConfigData.heli.CorrectionAngle = m_ccpm->ccpmCorrectionAngle->value();
|
||||
|
||||
config.heli.CorrectionAngle = m_ccpm->ccpmCorrectionAngle->value();
|
||||
|
||||
//update sliders
|
||||
if (useCCPM)
|
||||
if (useCCPM)
|
||||
{
|
||||
GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveSlider->value();
|
||||
config.heli.SliderValue0 = m_ccpm->ccpmCollectiveSlider->value();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveScale->value();
|
||||
config.heli.SliderValue0 = m_ccpm->ccpmCollectiveScale->value();
|
||||
}
|
||||
if (useCyclic)
|
||||
if (useCyclic)
|
||||
{
|
||||
GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmCyclicScale->value();
|
||||
config.heli.SliderValue1 = m_ccpm->ccpmCyclicScale->value();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmPitchScale->value();
|
||||
}
|
||||
GUIConfigData.heli.SliderValue2 = m_ccpm->ccpmRollScale->value();
|
||||
|
||||
config.heli.SliderValue1 = m_ccpm->ccpmPitchScale->value();
|
||||
}
|
||||
config.heli.SliderValue2 = m_ccpm->ccpmRollScale->value();
|
||||
|
||||
//servo assignments
|
||||
GUIConfigData.heli.ServoIndexW = m_ccpm->ccpmServoWChannel->currentIndex();
|
||||
GUIConfigData.heli.ServoIndexX = m_ccpm->ccpmServoXChannel->currentIndex();
|
||||
GUIConfigData.heli.ServoIndexY = m_ccpm->ccpmServoYChannel->currentIndex();
|
||||
GUIConfigData.heli.ServoIndexZ = m_ccpm->ccpmServoZChannel->currentIndex();
|
||||
|
||||
config.heli.ServoIndexW = m_ccpm->ccpmServoWChannel->currentIndex();
|
||||
config.heli.ServoIndexX = m_ccpm->ccpmServoXChannel->currentIndex();
|
||||
config.heli.ServoIndexY = m_ccpm->ccpmServoYChannel->currentIndex();
|
||||
config.heli.ServoIndexZ = m_ccpm->ccpmServoZChannel->currentIndex();
|
||||
|
||||
//throttle
|
||||
config.heli.Throttle = m_ccpm->ccpmEngineChannel->currentIndex();
|
||||
//tail
|
||||
config.heli.Tail = m_ccpm->ccpmTailChannel->currentIndex();
|
||||
|
||||
SetConfigData(config);
|
||||
|
||||
updatingFromHardware = FALSE;
|
||||
return airframeType;
|
||||
}
|
||||
void ConfigccpmWidget::UpdateCCPMUIFromOptions()
|
||||
|
||||
QString ConfigCcpmWidget::updateConfigObjectsFromWidgets() //UpdateCCPMOptionsFromUI()
|
||||
{
|
||||
QString airframeType = updateConfigObjects();
|
||||
|
||||
setMixer();
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
|
||||
void ConfigCcpmWidget::refreshWidgetsValues(QString frameType) //UpdateCCPMUIFromOptions()
|
||||
{
|
||||
Q_UNUSED(frameType);
|
||||
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
|
||||
//swashplate config
|
||||
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - (GUIConfigData.heli.SwasplateType +1));
|
||||
m_ccpm->ccpmSingleServo->setCurrentIndex(GUIConfigData.heli.FirstServoIndex);
|
||||
setComboCurrentIndex( m_ccpm->ccpmType, m_ccpm->ccpmType->count() - (config.heli.SwashplateType +1));
|
||||
setComboCurrentIndex(m_ccpm->ccpmSingleServo, config.heli.FirstServoIndex);
|
||||
|
||||
//ccpm mixing options
|
||||
m_ccpm->ccpmCollectivePassthrough->setChecked(GUIConfigData.heli.ccpmCollectivePassthroughState);
|
||||
m_ccpm->ccpmLinkCyclic->setChecked(GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
m_ccpm->ccpmLinkRoll->setChecked(GUIConfigData.heli.ccpmLinkRollState);
|
||||
m_ccpm->ccpmCollectivePassthrough->setChecked(config.heli.ccpmCollectivePassthroughState);
|
||||
m_ccpm->ccpmLinkCyclic->setChecked(config.heli.ccpmLinkCyclicState);
|
||||
m_ccpm->ccpmLinkRoll->setChecked(config.heli.ccpmLinkRollState);
|
||||
|
||||
//correction angle
|
||||
m_ccpm->ccpmCorrectionAngle->setValue(GUIConfigData.heli.CorrectionAngle);
|
||||
m_ccpm->ccpmCorrectionAngle->setValue(config.heli.CorrectionAngle);
|
||||
|
||||
//update sliders
|
||||
m_ccpm->ccpmCollectiveScale->setValue(GUIConfigData.heli.SliderValue0);
|
||||
m_ccpm->ccpmCollectiveScaleBox->setValue(GUIConfigData.heli.SliderValue0);
|
||||
m_ccpm->ccpmCyclicScale->setValue(GUIConfigData.heli.SliderValue1);
|
||||
m_ccpm->ccpmCyclicScaleBox->setValue(GUIConfigData.heli.SliderValue1);
|
||||
m_ccpm->ccpmPitchScale->setValue(GUIConfigData.heli.SliderValue1);
|
||||
m_ccpm->ccpmPitchScaleBox->setValue(GUIConfigData.heli.SliderValue1);
|
||||
m_ccpm->ccpmRollScale->setValue(GUIConfigData.heli.SliderValue2);
|
||||
m_ccpm->ccpmRollScaleBox->setValue(GUIConfigData.heli.SliderValue2);
|
||||
m_ccpm->ccpmCollectiveSlider->setValue(GUIConfigData.heli.SliderValue0);
|
||||
m_ccpm->ccpmCollectivespinBox->setValue(GUIConfigData.heli.SliderValue0);
|
||||
m_ccpm->ccpmCollectiveScale->setValue(config.heli.SliderValue0);
|
||||
m_ccpm->ccpmCollectiveScaleBox->setValue(config.heli.SliderValue0);
|
||||
m_ccpm->ccpmCyclicScale->setValue(config.heli.SliderValue1);
|
||||
m_ccpm->ccpmCyclicScaleBox->setValue(config.heli.SliderValue1);
|
||||
m_ccpm->ccpmPitchScale->setValue(config.heli.SliderValue1);
|
||||
m_ccpm->ccpmPitchScaleBox->setValue(config.heli.SliderValue1);
|
||||
m_ccpm->ccpmRollScale->setValue(config.heli.SliderValue2);
|
||||
m_ccpm->ccpmRollScaleBox->setValue(config.heli.SliderValue2);
|
||||
m_ccpm->ccpmCollectiveSlider->setValue(config.heli.SliderValue0);
|
||||
m_ccpm->ccpmCollectivespinBox->setValue(config.heli.SliderValue0);
|
||||
|
||||
//servo assignments
|
||||
m_ccpm->ccpmServoWChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexW);
|
||||
m_ccpm->ccpmServoXChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexX);
|
||||
m_ccpm->ccpmServoYChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexY);
|
||||
m_ccpm->ccpmServoZChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexZ);
|
||||
setComboCurrentIndex(m_ccpm->ccpmServoWChannel, config.heli.ServoIndexW);
|
||||
setComboCurrentIndex( m_ccpm->ccpmServoXChannel,config.heli.ServoIndexX);
|
||||
setComboCurrentIndex( m_ccpm->ccpmServoYChannel,config.heli.ServoIndexY);
|
||||
setComboCurrentIndex( m_ccpm->ccpmServoZChannel,config.heli.ServoIndexZ);
|
||||
|
||||
//throttle
|
||||
setComboCurrentIndex( m_ccpm->ccpmEngineChannel, config.heli.Throttle);
|
||||
//tail
|
||||
setComboCurrentIndex( m_ccpm->ccpmTailChannel, config.heli.Tail);
|
||||
|
||||
getMixer();
|
||||
}
|
||||
|
||||
|
||||
void ConfigccpmWidget::SetUIComponentVisibilities()
|
||||
void ConfigCcpmWidget::SetUIComponentVisibilities()
|
||||
{
|
||||
UpdateCCPMOptionsFromUI();
|
||||
//set which sliders are user...
|
||||
m_ccpm->ccpmRevoMixingBox->setVisible(0);
|
||||
|
||||
m_ccpm->ccpmPitchMixingBox->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
m_ccpm->ccpmCollectiveScalingBox->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
|
||||
m_ccpm->ccpmPitchMixingBox->setVisible(!m_ccpm->ccpmCollectivePassthrough->isChecked() &&
|
||||
m_ccpm->ccpmLinkCyclic->isChecked());
|
||||
|
||||
m_ccpm->ccpmLinkCyclic->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState);
|
||||
|
||||
m_ccpm->ccpmCyclicScalingBox->setVisible((GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState) && GUIConfigData.heli.ccpmLinkRollState);
|
||||
if (!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState)
|
||||
m_ccpm->ccpmCollectiveScalingBox->setVisible(m_ccpm->ccpmCollectivePassthrough->isChecked() || !m_ccpm->ccpmLinkCyclic->isChecked());
|
||||
|
||||
m_ccpm->ccpmLinkCyclic->setVisible(!m_ccpm->ccpmCollectivePassthrough->isChecked());
|
||||
|
||||
m_ccpm->ccpmCyclicScalingBox->setVisible((m_ccpm->ccpmCollectivePassthrough->isChecked() || !m_ccpm->ccpmLinkCyclic->isChecked()) &&
|
||||
m_ccpm->ccpmLinkRoll->isChecked());
|
||||
|
||||
if (!m_ccpm->ccpmCollectivePassthrough->checkState() && m_ccpm->ccpmLinkCyclic->isChecked())
|
||||
{
|
||||
m_ccpm->ccpmPitchScalingBox->setVisible(0);
|
||||
m_ccpm->ccpmRollScalingBox->setVisible(0);
|
||||
m_ccpm->ccpmLinkRoll->setVisible(0);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmPitchScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState);
|
||||
m_ccpm->ccpmRollScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState);
|
||||
m_ccpm->ccpmPitchScalingBox->setVisible(!m_ccpm->ccpmLinkRoll->isChecked());
|
||||
m_ccpm->ccpmRollScalingBox->setVisible(!m_ccpm->ccpmLinkRoll->isChecked());
|
||||
m_ccpm->ccpmLinkRoll->setVisible(1);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
Request the current value of the SystemSettings which holds the ccpm type
|
||||
*/
|
||||
void ConfigccpmWidget::requestccpmUpdate()
|
||||
void ConfigCcpmWidget::getMixer()
|
||||
{
|
||||
#define MaxAngleError 2
|
||||
int MixerDataFromHeli[8][5];
|
||||
quint8 MixerOutputType[8];
|
||||
int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],ServoCurve2[4];
|
||||
int NumServos=0;
|
||||
|
||||
if (SwashLvlConfigurationInProgress)return;
|
||||
if (updatingToHardware)return;
|
||||
updatingFromHardware=TRUE;
|
||||
|
||||
unsigned int i,j;
|
||||
|
||||
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(systemSettings);
|
||||
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
|
||||
|
||||
Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM ==
|
||||
(sizeof(GUIConfigData.UAVObject) / sizeof(GUIConfigData.UAVObject[0])));
|
||||
|
||||
for(i = 0; i < SystemSettings::GUICONFIGDATA_NUMELEM; i++)
|
||||
GUIConfigData.UAVObject[i]=systemSettingsData.GUIConfigData[i];
|
||||
|
||||
UpdateCCPMUIFromOptions();
|
||||
int i;
|
||||
|
||||
// Get existing mixer settings
|
||||
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
|
||||
MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();
|
||||
|
||||
//go through the user data and update the mixer matrix
|
||||
for (j=0;j<5;j++)
|
||||
{
|
||||
MixerDataFromHeli[0][j] = mixerSettingsData.Mixer1Vector[j];
|
||||
MixerDataFromHeli[1][j] = mixerSettingsData.Mixer2Vector[j];
|
||||
MixerDataFromHeli[2][j] = mixerSettingsData.Mixer3Vector[j];
|
||||
MixerDataFromHeli[3][j] = mixerSettingsData.Mixer4Vector[j];
|
||||
MixerDataFromHeli[4][j] = mixerSettingsData.Mixer5Vector[j];
|
||||
MixerDataFromHeli[5][j] = mixerSettingsData.Mixer6Vector[j];
|
||||
MixerDataFromHeli[6][j] = mixerSettingsData.Mixer7Vector[j];
|
||||
MixerDataFromHeli[7][j] = mixerSettingsData.Mixer8Vector[j];
|
||||
}
|
||||
|
||||
MixerOutputType[0] = mixerSettingsData.Mixer1Type;
|
||||
MixerOutputType[1] = mixerSettingsData.Mixer2Type;
|
||||
MixerOutputType[2] = mixerSettingsData.Mixer3Type;
|
||||
MixerOutputType[3] = mixerSettingsData.Mixer4Type;
|
||||
MixerOutputType[4] = mixerSettingsData.Mixer5Type;
|
||||
MixerOutputType[5] = mixerSettingsData.Mixer6Type;
|
||||
MixerOutputType[6] = mixerSettingsData.Mixer7Type;
|
||||
MixerOutputType[7] = mixerSettingsData.Mixer8Type;
|
||||
|
||||
EngineChannel =-1;
|
||||
TailRotorChannel =-1;
|
||||
for (j=0;j<5;j++)
|
||||
{
|
||||
ServoChannels[j]=8;
|
||||
ServoCurve2[j]=0;
|
||||
ServoAngles[j]=0;
|
||||
SortAngles[j]=j;
|
||||
}
|
||||
|
||||
NumServos=0;
|
||||
//process the data from Heli and try to figure out the settings...
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
//check if this is the engine... Throttle only
|
||||
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_MOTOR)&&
|
||||
(MixerDataFromHeli[i][0]>0)&&//ThrottleCurve1
|
||||
(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
|
||||
(MixerDataFromHeli[i][2]==0)&&//Roll
|
||||
(MixerDataFromHeli[i][3]==0)&&//Pitch
|
||||
(MixerDataFromHeli[i][4]==0))//Yaw
|
||||
{
|
||||
EngineChannel = i;
|
||||
m_ccpm->ccpmEngineChannel->setCurrentIndex(i);
|
||||
|
||||
}
|
||||
//check if this is the tail rotor... REVO and YAW
|
||||
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&&
|
||||
//(MixerDataFromHeli[i][0]!=0)&&//ThrottleCurve1
|
||||
(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
|
||||
(MixerDataFromHeli[i][2]==0)&&//Roll
|
||||
(MixerDataFromHeli[i][3]==0)&&//Pitch
|
||||
(MixerDataFromHeli[i][4]!=0))//Yaw
|
||||
{
|
||||
TailRotorChannel = i;
|
||||
m_ccpm->ccpmTailChannel->setCurrentIndex(i);
|
||||
m_ccpm->ccpmRevoSlider->setValue((MixerDataFromHeli[i][0]*100)/127);
|
||||
m_ccpm->ccpmREVOspinBox->setValue((MixerDataFromHeli[i][0]*100)/127);
|
||||
}
|
||||
//check if this is a swashplate servo... Throttle is zero
|
||||
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&&
|
||||
(MixerDataFromHeli[i][0]==0)&&//ThrottleCurve1
|
||||
//(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
|
||||
//(MixerDataFromHeli[i][2]==0)&&//Roll
|
||||
//(MixerDataFromHeli[i][3]==0)&&//Pitch
|
||||
(MixerDataFromHeli[i][4]==0))//Yaw
|
||||
{
|
||||
ServoChannels[NumServos] = i;//record the channel for this servo
|
||||
ServoCurve2[NumServos]=MixerDataFromHeli[i][1];//record the ThrottleCurve2 contribution to this servo
|
||||
ServoAngles[NumServos]=NumServos*45;//make this 0 for the final version
|
||||
|
||||
NumServos++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//get the settings for the curve from the mixer settings
|
||||
for (i=0;i<5;i++)
|
||||
@ -1221,7 +1159,7 @@ void ConfigccpmWidget::requestccpmUpdate()
|
||||
}
|
||||
|
||||
updatingFromHardware=FALSE;
|
||||
UpdateCCPMUIFromOptions();
|
||||
|
||||
ccpmSwashplateUpdate();
|
||||
}
|
||||
|
||||
@ -1229,25 +1167,15 @@ void ConfigccpmWidget::requestccpmUpdate()
|
||||
/**
|
||||
Sends the config to the board (ccpm type)
|
||||
*/
|
||||
void ConfigccpmWidget::sendccpmUpdate()
|
||||
void ConfigCcpmWidget::setMixer()
|
||||
{
|
||||
int i,j;
|
||||
|
||||
if (SwashLvlConfigurationInProgress)return;
|
||||
updatingToHardware=TRUE;
|
||||
//ShowDisclaimer(1);
|
||||
|
||||
UpdateCCPMOptionsFromUI();
|
||||
if (updatingToHardware == TRUE) return;
|
||||
|
||||
updatingToHardware=TRUE;
|
||||
|
||||
// Store the data required to reconstruct
|
||||
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(systemSettings);
|
||||
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
|
||||
systemSettingsData.GUIConfigData[0] = GUIConfigData.UAVObject[0];
|
||||
systemSettingsData.GUIConfigData[1] = GUIConfigData.UAVObject[1];
|
||||
systemSettings->setData(systemSettingsData);
|
||||
systemSettings->updated();
|
||||
|
||||
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(mixerSettings);
|
||||
MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();
|
||||
@ -1276,19 +1204,23 @@ void ConfigccpmWidget::sendccpmUpdate()
|
||||
&mixerSettingsData.Mixer8Type
|
||||
};
|
||||
|
||||
//reset all to Disabled
|
||||
for (i=0; i<8; i++)
|
||||
*mixerTypes[i] = 0;
|
||||
|
||||
//go through the user data and update the mixer matrix
|
||||
for (i=0;i<6;i++)
|
||||
{
|
||||
if (MixerChannelData[i]<8)
|
||||
if (MixerChannelData[i]>0)
|
||||
{
|
||||
//set the mixer type
|
||||
*(mixerTypes[MixerChannelData[i]]) = i==0 ?
|
||||
*(mixerTypes[MixerChannelData[i] - 1]) = i==0 ?
|
||||
MixerSettings::MIXER1TYPE_MOTOR :
|
||||
MixerSettings::MIXER1TYPE_SERVO;
|
||||
|
||||
//config the vector
|
||||
for (j=0;j<5;j++)
|
||||
mixers[MixerChannelData[i]][j] = m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt();
|
||||
mixers[MixerChannelData[i] - 1][j] = m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1302,7 +1234,7 @@ void ConfigccpmWidget::sendccpmUpdate()
|
||||
//mapping of collective input to curve 2...
|
||||
//MixerSettings.Curve2Source = Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5
|
||||
//check if we are using throttle or directly from a channel...
|
||||
if (GUIConfigData.heli.ccpmCollectivePassthroughState)
|
||||
if (m_ccpm->ccpmCollectivePassthrough->isChecked())
|
||||
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_COLLECTIVE;
|
||||
else
|
||||
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_THROTTLE;
|
||||
@ -1316,18 +1248,19 @@ void ConfigccpmWidget::sendccpmUpdate()
|
||||
/**
|
||||
Send ccpm type to the board and request saving to SD card
|
||||
*/
|
||||
void ConfigccpmWidget::saveccpmUpdate()
|
||||
void ConfigCcpmWidget::saveccpmUpdate()
|
||||
{
|
||||
if (SwashLvlConfigurationInProgress)return;
|
||||
ShowDisclaimer(0);
|
||||
// Send update so that the latest value is saved
|
||||
sendccpmUpdate();
|
||||
//sendccpmUpdate();
|
||||
setMixer();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
saveObjectToSD(obj);
|
||||
}
|
||||
|
||||
void ConfigccpmWidget::resizeEvent(QResizeEvent* event)
|
||||
void ConfigCcpmWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
// Make the custom table columns autostretch:
|
||||
@ -1339,7 +1272,7 @@ void ConfigccpmWidget::resizeEvent(QResizeEvent* event)
|
||||
ccpmSwashplateRedraw();
|
||||
|
||||
}
|
||||
void ConfigccpmWidget::showEvent(QShowEvent *event)
|
||||
void ConfigCcpmWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents();
|
||||
@ -1351,7 +1284,7 @@ void ConfigccpmWidget::showEvent(QShowEvent *event)
|
||||
}
|
||||
|
||||
|
||||
void ConfigccpmWidget::SwashLvlStartButtonPressed()
|
||||
void ConfigCcpmWidget::SwashLvlStartButtonPressed()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
int i;
|
||||
@ -1388,7 +1321,8 @@ void ConfigccpmWidget::SwashLvlStartButtonPressed()
|
||||
|
||||
|
||||
//download the current settings to the OP hw
|
||||
sendccpmUpdate();
|
||||
//sendccpmUpdate();
|
||||
setMixer();
|
||||
|
||||
//change control mode to gcs control / disarmed
|
||||
//set throttle to 0
|
||||
@ -1413,10 +1347,10 @@ void ConfigccpmWidget::SwashLvlStartButtonPressed()
|
||||
oldSwashLvlConfiguration.ServoChannels[2]=m_ccpm->ccpmServoYChannel->currentIndex();
|
||||
oldSwashLvlConfiguration.ServoChannels[3]=m_ccpm->ccpmServoZChannel->currentIndex();
|
||||
//if servos are used
|
||||
oldSwashLvlConfiguration.Used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
|
||||
oldSwashLvlConfiguration.Used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
|
||||
oldSwashLvlConfiguration.Used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
|
||||
oldSwashLvlConfiguration.Used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
|
||||
oldSwashLvlConfiguration.Used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()>0)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
|
||||
oldSwashLvlConfiguration.Used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()>0)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
|
||||
oldSwashLvlConfiguration.Used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()>0)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
|
||||
oldSwashLvlConfiguration.Used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()>0)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
|
||||
//min,neutral,max values for the servos
|
||||
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
|
||||
{
|
||||
@ -1449,7 +1383,7 @@ void ConfigccpmWidget::SwashLvlStartButtonPressed()
|
||||
|
||||
|
||||
}
|
||||
void ConfigccpmWidget::SwashLvlNextButtonPressed()
|
||||
void ConfigCcpmWidget::SwashLvlNextButtonPressed()
|
||||
{
|
||||
//ShowDisclaimer(2);
|
||||
SwashLvlState++;
|
||||
@ -1552,7 +1486,7 @@ void ConfigccpmWidget::SwashLvlNextButtonPressed()
|
||||
break;
|
||||
}
|
||||
}
|
||||
void ConfigccpmWidget::SwashLvlCancelButtonPressed()
|
||||
void ConfigCcpmWidget::SwashLvlCancelButtonPressed()
|
||||
{
|
||||
int i;
|
||||
SwashLvlState=0;
|
||||
@ -1600,7 +1534,7 @@ void ConfigccpmWidget::SwashLvlCancelButtonPressed()
|
||||
}
|
||||
|
||||
|
||||
void ConfigccpmWidget::SwashLvlFinishButtonPressed()
|
||||
void ConfigCcpmWidget::SwashLvlFinishButtonPressed()
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1644,7 +1578,7 @@ void ConfigccpmWidget::SwashLvlFinishButtonPressed()
|
||||
|
||||
}
|
||||
|
||||
int ConfigccpmWidget::ShowDisclaimer(int messageID)
|
||||
int ConfigCcpmWidget::ShowDisclaimer(int messageID)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("<font color=red><h1>Warning!!!</h2></font>");
|
||||
@ -1693,7 +1627,7 @@ int ConfigccpmWidget::ShowDisclaimer(int messageID)
|
||||
Toggles the channel testing mode by making the GCS take over
|
||||
the ActuatorCommand objects
|
||||
*/
|
||||
void ConfigccpmWidget::enableSwashplateLevellingControl(bool state)
|
||||
void ConfigCcpmWidget::enableSwashplateLevellingControl(bool state)
|
||||
{
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
@ -1733,7 +1667,7 @@ void ConfigccpmWidget::enableSwashplateLevellingControl(bool state)
|
||||
Sets the swashplate level to a given value based on current settings for Max, Neutral and Min values.
|
||||
level ranges -1 to +1
|
||||
*/
|
||||
void ConfigccpmWidget::setSwashplateLevel(int percent)
|
||||
void ConfigCcpmWidget::setSwashplateLevel(int percent)
|
||||
{
|
||||
if (percent<0)return;// -1;
|
||||
if (percent>100)return;// -1;
|
||||
@ -1768,7 +1702,7 @@ return;
|
||||
}
|
||||
|
||||
|
||||
void ConfigccpmWidget::SwashLvlSpinBoxChanged(int value)
|
||||
void ConfigCcpmWidget::SwashLvlSpinBoxChanged(int value)
|
||||
{
|
||||
Q_UNUSED(value);
|
||||
int i;
|
||||
@ -1808,3 +1742,63 @@ void ConfigccpmWidget::SwashLvlSpinBoxChanged(int value)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
|
||||
*/
|
||||
void ConfigCcpmWidget::throwConfigError(QString airframeType)
|
||||
{
|
||||
Q_UNUSED(airframeType);
|
||||
|
||||
if((m_ccpm->ccpmServoWChannel->currentIndex()==0)&&(m_ccpm->ccpmServoWChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoWLabel->setText("<font color=red>Servo W</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoWLabel->setText("<font color=black>Servo W</font>");
|
||||
}
|
||||
if((m_ccpm->ccpmServoXChannel->currentIndex()==0)&&(m_ccpm->ccpmServoXChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoXLabel->setText("<font color=red>Servo X</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoXLabel->setText("<font color=black>Servo X</font>");
|
||||
}
|
||||
if((m_ccpm->ccpmServoYChannel->currentIndex()==0)&&(m_ccpm->ccpmServoYChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoYLabel->setText("<font color=red>Servo Y</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoYLabel->setText("<font color=black>Servo Y</font>");
|
||||
}
|
||||
if((m_ccpm->ccpmServoZChannel->currentIndex()==0)&&(m_ccpm->ccpmServoZChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmServoZLabel->setText("<font color=red>Servo Z</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmServoZLabel->setText("<font color=black>Servo Z</font>");
|
||||
}
|
||||
|
||||
if((m_ccpm->ccpmEngineChannel->currentIndex()==0)&&(m_ccpm->ccpmEngineChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmEngineLabel->setText("<font color=red>Engine</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmEngineLabel->setText("<font color=black>Engine</font>");
|
||||
}
|
||||
|
||||
if((m_ccpm->ccpmTailChannel->currentIndex()==0)&&(m_ccpm->ccpmTailChannel->isEnabled()))
|
||||
{
|
||||
m_ccpm->ccpmTailLabel->setText("<font color=red>Tail Rotor</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ccpm->ccpmTailLabel->setText("<font color=black>Tail Rotor</font>");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "ui_ccpm.h"
|
||||
#include "../uavobjectwidgetutils/configtaskwidget.h"
|
||||
#include "cfg_vehicletypes/vehicleconfig.h"
|
||||
#include "extensionsystem/pluginmanager.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
@ -50,36 +51,14 @@ typedef struct {
|
||||
int Min[CCPM_MAX_SWASH_SERVOS];
|
||||
} SwashplateServoSettingsStruct;
|
||||
|
||||
typedef struct {
|
||||
uint SwasplateType:3;
|
||||
uint FirstServoIndex:2;
|
||||
uint CorrectionAngle:9;
|
||||
uint ccpmCollectivePassthroughState:1;
|
||||
uint ccpmLinkCyclicState:1;
|
||||
uint ccpmLinkRollState:1;
|
||||
uint SliderValue0:7;
|
||||
uint SliderValue1:7;
|
||||
uint SliderValue2:7;//41bits
|
||||
uint ServoIndexW:4;
|
||||
uint ServoIndexX:4;
|
||||
uint ServoIndexY:4;
|
||||
uint ServoIndexZ:4;//57bits
|
||||
uint padding:7;
|
||||
} __attribute__((packed)) heliGUISettingsStruct;
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint UAVObject[2];//32bits * 2
|
||||
heliGUISettingsStruct heli;//64bits
|
||||
} GUIConfigDataUnion;
|
||||
|
||||
class ConfigccpmWidget: public ConfigTaskWidget
|
||||
class ConfigCcpmWidget: public VehicleConfig
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfigccpmWidget(QWidget *parent = 0);
|
||||
~ConfigccpmWidget();
|
||||
ConfigCcpmWidget(QWidget *parent = 0);
|
||||
~ConfigCcpmWidget();
|
||||
|
||||
friend class ConfigVehicleTypeWidget;
|
||||
|
||||
@ -87,14 +66,6 @@ private:
|
||||
Ui_ccpmWidget *m_ccpm;
|
||||
QGraphicsSvgItem *SwashplateImg;
|
||||
QGraphicsSvgItem *CurveImg;
|
||||
//QGraphicsSvgItem *ServoW;
|
||||
//QGraphicsSvgItem *ServoX;
|
||||
//QGraphicsSvgItem *ServoY;
|
||||
//QGraphicsSvgItem *ServoZ;
|
||||
//QGraphicsTextItem *ServoWText;
|
||||
//QGraphicsTextItem *ServoXText;
|
||||
//QGraphicsTextItem *ServoYText;
|
||||
//QGraphicsTextItem *ServoZText;
|
||||
QGraphicsSvgItem *Servos[CCPM_MAX_SWASH_SERVOS];
|
||||
QGraphicsTextItem *ServosText[CCPM_MAX_SWASH_SERVOS];
|
||||
QGraphicsLineItem *ServoLines[CCPM_MAX_SWASH_SERVOS];
|
||||
@ -109,8 +80,6 @@ private:
|
||||
SwashplateServoSettingsStruct oldSwashLvlConfiguration;
|
||||
SwashplateServoSettingsStruct newSwashLvlConfiguration;
|
||||
|
||||
GUIConfigDataUnion GUIConfigData;
|
||||
|
||||
int MixerChannelData[6];
|
||||
int ShowDisclaimer(int messageID);
|
||||
virtual void enableControls(bool enable) { Q_UNUSED(enable)}; // Not used by this widget
|
||||
@ -118,7 +87,16 @@ private:
|
||||
bool updatingFromHardware;
|
||||
bool updatingToHardware;
|
||||
|
||||
virtual void ResetActuators(GUIConfigDataUnion* configData);
|
||||
virtual QStringList getChannelDescriptions();
|
||||
|
||||
QString updateConfigObjects();
|
||||
private slots:
|
||||
virtual void setupUI(QString airframeType);
|
||||
virtual void refreshWidgetsValues(QString frameType);
|
||||
virtual QString updateConfigObjectsFromWidgets();
|
||||
virtual void throwConfigError(QString airframeType);
|
||||
|
||||
void ccpmSwashplateUpdate();
|
||||
void ccpmSwashplateRedraw();
|
||||
void UpdateCurveSettings();
|
||||
@ -135,11 +113,10 @@ private:
|
||||
void SwashLvlCancelButtonPressed();
|
||||
void SwashLvlFinishButtonPressed();
|
||||
|
||||
void UpdateCCPMOptionsFromUI();
|
||||
void UpdateCCPMUIFromOptions();
|
||||
//void UpdateCCPMOptionsFromUI();
|
||||
//void UpdateCCPMUIFromOptions();
|
||||
|
||||
void SetUIComponentVisibilities();
|
||||
void ccpmChannelCheck();
|
||||
|
||||
void enableSwashplateLevellingControl(bool state);
|
||||
void setSwashplateLevel(int percent);
|
||||
@ -147,8 +124,8 @@ private:
|
||||
virtual void refreshValues() {}; // Not used
|
||||
|
||||
public slots:
|
||||
void requestccpmUpdate();
|
||||
void sendccpmUpdate();
|
||||
void getMixer();
|
||||
void setMixer();
|
||||
void saveccpmUpdate();
|
||||
|
||||
protected:
|
||||
|
@ -24,7 +24,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
//#include "configfixedwingwidget.h"
|
||||
#include "configfixedwingwidget.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
#include "mixersettings.h"
|
||||
|
||||
@ -40,18 +40,38 @@
|
||||
|
||||
#include "mixersettings.h"
|
||||
#include "systemsettings.h"
|
||||
#include "actuatorsettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
|
||||
|
||||
/**
|
||||
Helper function to setup the UI
|
||||
Constructor
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupFixedWingUI(QString frameType)
|
||||
ConfigFixedWingWidget::ConfigFixedWingWidget(Ui_AircraftWidget *aircraft, QWidget *parent) : VehicleConfig(parent)
|
||||
{
|
||||
m_aircraft = aircraft;
|
||||
}
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
ConfigFixedWingWidget::~ConfigFixedWingWidget()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Virtual function to setup the UI
|
||||
*/
|
||||
void ConfigFixedWingWidget::setupUI(QString frameType)
|
||||
{
|
||||
Q_ASSERT(m_aircraft);
|
||||
|
||||
if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") {
|
||||
// Setup the UI
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder"));
|
||||
setComboCurrentIndex(m_aircraft->aircraftType, m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
setComboCurrentIndex(m_aircraft->fixedWingType, m_aircraft->fixedWingType->findText("Elevator aileron rudder"));
|
||||
m_aircraft->fwRudder1ChannelBox->setEnabled(true);
|
||||
m_aircraft->fwRudder1Label->setEnabled(true);
|
||||
m_aircraft->fwRudder2ChannelBox->setEnabled(true);
|
||||
@ -72,8 +92,8 @@ void ConfigVehicleTypeWidget::setupFixedWingUI(QString frameType)
|
||||
m_aircraft->elevonMixBox->setHidden(true);
|
||||
|
||||
} else if (frameType == "FixedWingElevon" || frameType == "Elevon") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon"));
|
||||
setComboCurrentIndex(m_aircraft->aircraftType, m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
setComboCurrentIndex(m_aircraft->fixedWingType, m_aircraft->fixedWingType->findText("Elevon"));
|
||||
m_aircraft->fwAileron1Label->setText("Elevon 1");
|
||||
m_aircraft->fwAileron2Label->setText("Elevon 2");
|
||||
m_aircraft->fwElevator1ChannelBox->setEnabled(false);
|
||||
@ -91,8 +111,8 @@ void ConfigVehicleTypeWidget::setupFixedWingUI(QString frameType)
|
||||
m_aircraft->elevonLabel2->setText("Pitch");
|
||||
|
||||
} else if (frameType == "FixedWingVtail" || frameType == "Vtail") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail"));
|
||||
setComboCurrentIndex(m_aircraft->aircraftType, m_aircraft->aircraftType->findText("Fixed Wing"));
|
||||
setComboCurrentIndex(m_aircraft->fixedWingType, m_aircraft->fixedWingType->findText("Vtail"));
|
||||
m_aircraft->fwRudder1ChannelBox->setEnabled(false);
|
||||
m_aircraft->fwRudder1Label->setEnabled(false);
|
||||
m_aircraft->fwRudder2ChannelBox->setEnabled(false);
|
||||
@ -111,12 +131,53 @@ void ConfigVehicleTypeWidget::setupFixedWingUI(QString frameType)
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigFixedWingWidget::ResetActuators(GUIConfigDataUnion* configData)
|
||||
{
|
||||
configData->fixedwing.FixedWingPitch1 = 0;
|
||||
configData->fixedwing.FixedWingPitch2 = 0;
|
||||
configData->fixedwing.FixedWingRoll1 = 0;
|
||||
configData->fixedwing.FixedWingRoll2 = 0;
|
||||
configData->fixedwing.FixedWingYaw1 = 0;
|
||||
configData->fixedwing.FixedWingYaw2 = 0;
|
||||
configData->fixedwing.FixedWingThrottle = 0;
|
||||
}
|
||||
|
||||
QStringList ConfigFixedWingWidget::getChannelDescriptions()
|
||||
{
|
||||
int i;
|
||||
QStringList channelDesc;
|
||||
|
||||
// init a channel_numelem list of channel desc defaults
|
||||
for (i=0; i < (int)(ConfigFixedWingWidget::CHANNEL_NUMELEM); i++)
|
||||
{
|
||||
channelDesc.append(QString("-"));
|
||||
}
|
||||
|
||||
// get the gui config data
|
||||
GUIConfigDataUnion configData = GetConfigData();
|
||||
|
||||
if (configData.fixedwing.FixedWingPitch1 > 0)
|
||||
channelDesc[configData.fixedwing.FixedWingPitch1-1] = QString("FixedWingPitch1");
|
||||
if (configData.fixedwing.FixedWingPitch2 > 0)
|
||||
channelDesc[configData.fixedwing.FixedWingPitch2-1] = QString("FixedWingPitch2");
|
||||
if (configData.fixedwing.FixedWingRoll1 > 0)
|
||||
channelDesc[configData.fixedwing.FixedWingRoll1-1] = QString("FixedWingRoll1");
|
||||
if (configData.fixedwing.FixedWingRoll2 > 0)
|
||||
channelDesc[configData.fixedwing.FixedWingRoll2-1] = QString("FixedWingRoll2");
|
||||
if (configData.fixedwing.FixedWingYaw1 > 0)
|
||||
channelDesc[configData.fixedwing.FixedWingYaw1-1] = QString("FixedWingYaw1");
|
||||
if (configData.fixedwing.FixedWingYaw2 > 0)
|
||||
channelDesc[configData.fixedwing.FixedWingYaw2-1] = QString("FixedWingYaw2");
|
||||
if (configData.fixedwing.FixedWingThrottle > 0)
|
||||
channelDesc[configData.fixedwing.FixedWingThrottle-1] = QString("FixedWingThrottle");
|
||||
|
||||
return channelDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
Helper function to update the UI widget objects
|
||||
Virtual function to update the UI widget objects
|
||||
*/
|
||||
QString ConfigVehicleTypeWidget::updateFixedWingObjectsFromWidgets()
|
||||
QString ConfigFixedWingWidget::updateConfigObjectsFromWidgets()
|
||||
{
|
||||
QString airframeType = "FixedWing";
|
||||
|
||||
@ -136,7 +197,7 @@ QString ConfigVehicleTypeWidget::updateFixedWingObjectsFromWidgets()
|
||||
//All airframe types must start with "FixedWing"
|
||||
if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) {
|
||||
airframeType = "FixedWing";
|
||||
setupFrameFixedWing( airframeType );
|
||||
setupFrameFixedWing( airframeType );
|
||||
} else if (m_aircraft->fixedWingType->currentText() == "Elevon") {
|
||||
airframeType = "FixedWingElevon";
|
||||
setupFrameElevon( airframeType );
|
||||
@ -144,54 +205,33 @@ QString ConfigVehicleTypeWidget::updateFixedWingObjectsFromWidgets()
|
||||
airframeType = "FixedWingVtail";
|
||||
setupFrameVtail( airframeType );
|
||||
}
|
||||
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper function to refresh the UI widget values
|
||||
Virtual function to refresh the UI widget values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshFixedWingWidgetsValues(QString frameType)
|
||||
void ConfigFixedWingWidget::refreshWidgetsValues(QString frameType)
|
||||
{
|
||||
|
||||
UAVDataObject* obj;
|
||||
UAVObjectField *field;
|
||||
|
||||
// Then retrieve how channels are setup
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("FixedWingThrottle"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString()));
|
||||
Q_ASSERT(m_aircraft);
|
||||
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
fixedGUISettingsStruct fixed = config.fixedwing;
|
||||
|
||||
// Then retrieve how channels are setup
|
||||
setComboCurrentIndex(m_aircraft->fwEngineChannelBox, fixed.FixedWingThrottle);
|
||||
setComboCurrentIndex(m_aircraft->fwAileron1ChannelBox, fixed.FixedWingRoll1);
|
||||
setComboCurrentIndex(m_aircraft->fwAileron2ChannelBox, fixed.FixedWingRoll2);
|
||||
setComboCurrentIndex(m_aircraft->fwElevator1ChannelBox, fixed.FixedWingPitch1);
|
||||
setComboCurrentIndex(m_aircraft->fwElevator2ChannelBox, fixed.FixedWingPitch2);
|
||||
setComboCurrentIndex(m_aircraft->fwRudder1ChannelBox, fixed.FixedWingYaw1);
|
||||
setComboCurrentIndex(m_aircraft->fwRudder2ChannelBox, fixed.FixedWingYaw2);
|
||||
|
||||
UAVDataObject* obj;
|
||||
UAVObjectField *field;
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingPitch1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingPitch2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingYaw1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingYaw2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
if (frameType == "FixedWingElevon") {
|
||||
// If the airframe is elevon, restore the slider setting
|
||||
// Find the channel number for Elevon1 (FixedWingRoll1)
|
||||
@ -230,11 +270,11 @@ void ConfigVehicleTypeWidget::refreshFixedWingWidgetsValues(QString frameType)
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupFrameFixedWing(QString airframeType)
|
||||
bool ConfigFixedWingWidget::setupFrameFixedWing(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwFixedWingChannelConfigError(airframeType);
|
||||
throwConfigError(airframeType);
|
||||
|
||||
// - At least Pitch and either Roll or Yaw
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
|
||||
@ -245,118 +285,67 @@ bool ConfigVehicleTypeWidget::setupFrameFixedWing(QString airframeType)
|
||||
// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
|
||||
return false;
|
||||
}
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevator
|
||||
UAVObjectField *field = obj->getField("FixedWingPitch1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingPitch2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
|
||||
|
||||
// Aileron
|
||||
field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
|
||||
// Rudder
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
|
||||
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
|
||||
// Now setup the channels:
|
||||
|
||||
obj->updated();
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
ResetActuators(&config);
|
||||
|
||||
config.fixedwing.FixedWingPitch1 = m_aircraft->fwElevator1ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingPitch2 = m_aircraft->fwElevator2ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingRoll1 = m_aircraft->fwAileron1ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingRoll2 = m_aircraft->fwAileron2ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingYaw1 = m_aircraft->fwRudder1ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingThrottle = m_aircraft->fwEngineChannelBox->currentIndex();
|
||||
|
||||
SetConfigData(config);
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
|
||||
int channel;
|
||||
//disable all
|
||||
for (channel=0; channel<VehicleConfig::CHANNEL_NUMELEM; channel++)
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_DISABLED);
|
||||
|
||||
//motor
|
||||
channel = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_MOTOR);
|
||||
setMixerVectorValue(mixer,channel,VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);
|
||||
|
||||
//rudder
|
||||
channel = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
|
||||
//ailerons
|
||||
channel = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (channel > -1) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, 127);
|
||||
|
||||
channel = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, 127);
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Rudder
|
||||
tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if rudder is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no rudder, only ailerons, we're fine with it.
|
||||
|
||||
// Ailerons
|
||||
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127, ti);
|
||||
// Only set Aileron 2 if Aileron 1 is defined
|
||||
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
} // Else we have no ailerons. Our consistency check guarantees we have
|
||||
// rudder in this case, so we're fine with it too.
|
||||
|
||||
// Elevator
|
||||
tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(127, ti);
|
||||
// Only set Elevator 2 if it is defined
|
||||
tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(127, ti);
|
||||
|
||||
//elevators
|
||||
channel = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
|
||||
if (channel > -1) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, 127);
|
||||
|
||||
channel = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, 127);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
|
||||
return true;
|
||||
@ -367,11 +356,11 @@ bool ConfigVehicleTypeWidget::setupFrameFixedWing(QString airframeType)
|
||||
/**
|
||||
Setup Elevon
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupFrameElevon(QString airframeType)
|
||||
bool ConfigFixedWingWidget::setupFrameElevon(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwFixedWingChannelConfigError(airframeType);
|
||||
throwConfigError(airframeType);
|
||||
|
||||
// - At least Aileron1 and Aileron 2, and engine
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
|
||||
@ -382,106 +371,64 @@ bool ConfigVehicleTypeWidget::setupFrameElevon(QString airframeType)
|
||||
return false;
|
||||
}
|
||||
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevons
|
||||
UAVObjectField *field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
// Rudder 1 (can be None)
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
|
||||
// Rudder 2 (can be None)
|
||||
field = obj->getField("FixedWingYaw2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwRudder2ChannelBox->currentText());
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
ResetActuators(&config);
|
||||
|
||||
config.fixedwing.FixedWingRoll1 = m_aircraft->fwAileron1ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingRoll2 = m_aircraft->fwAileron2ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingYaw1 = m_aircraft->fwRudder1ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingYaw2 = m_aircraft->fwRudder2ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingThrottle = m_aircraft->fwEngineChannelBox->currentIndex();
|
||||
|
||||
SetConfigData(config);
|
||||
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
// Save the curve:
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
|
||||
int channel;
|
||||
double value;
|
||||
//disable all
|
||||
for (channel=0; channel<VehicleConfig::CHANNEL_NUMELEM; channel++)
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_DISABLED);
|
||||
|
||||
//motor
|
||||
channel = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_MOTOR);
|
||||
setMixerVectorValue(mixer,channel,VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);
|
||||
|
||||
//rudders
|
||||
channel = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
|
||||
channel = m_aircraft->fwRudder2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -127);
|
||||
|
||||
//ailerons
|
||||
channel = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (channel > -1) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
value = (double)(m_aircraft->elevonSlider2->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, value);
|
||||
value = (double)(m_aircraft->elevonSlider1->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, value);
|
||||
|
||||
channel = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
value = (double)(m_aircraft->elevonSlider2->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, value);
|
||||
value = (double)(m_aircraft->elevonSlider1->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, -value);
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Rudder 1
|
||||
tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if rudder 1 is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no rudder, only elevons, we're fine with it.
|
||||
|
||||
// Rudder 2
|
||||
tmpVal = m_aircraft->fwRudder2ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if rudder 2 is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-127, ti);
|
||||
} // Else: we have no rudder, only elevons, we're fine with it.
|
||||
|
||||
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
}
|
||||
|
||||
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
return true;
|
||||
}
|
||||
@ -491,11 +438,11 @@ bool ConfigVehicleTypeWidget::setupFrameElevon(QString airframeType)
|
||||
/**
|
||||
Setup VTail
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupFrameVtail(QString airframeType)
|
||||
bool ConfigFixedWingWidget::setupFrameVtail(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwFixedWingChannelConfigError(airframeType);
|
||||
throwConfigError(airframeType);
|
||||
|
||||
// - At least Pitch1 and Pitch2, and engine
|
||||
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
|
||||
@ -506,97 +453,75 @@ bool ConfigVehicleTypeWidget::setupFrameVtail(QString airframeType)
|
||||
return false;
|
||||
}
|
||||
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Elevons
|
||||
UAVObjectField *field = obj->getField("FixedWingPitch1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingPitch2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
field = obj->getField("FixedWingRoll2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
|
||||
// Throttle
|
||||
field = obj->getField("FixedWingThrottle");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
ResetActuators(&config);
|
||||
|
||||
config.fixedwing.FixedWingPitch1 = m_aircraft->fwElevator1ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingPitch2 = m_aircraft->fwElevator2ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingRoll1 = m_aircraft->fwAileron1ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingRoll2 = m_aircraft->fwAileron2ChannelBox->currentIndex();
|
||||
config.fixedwing.FixedWingThrottle = m_aircraft->fwEngineChannelBox->currentIndex();
|
||||
|
||||
SetConfigData(config);
|
||||
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
// Save the curve:
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
// Disable all
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
field->setValue("Disabled");
|
||||
|
||||
int channel;
|
||||
double value;
|
||||
//disable all
|
||||
for (channel=0; channel<VehicleConfig::CHANNEL_NUMELEM; channel++)
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_DISABLED);
|
||||
|
||||
//motor
|
||||
channel = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_MOTOR);
|
||||
setMixerVectorValue(mixer,channel,VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);
|
||||
|
||||
//rudders
|
||||
channel = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
|
||||
channel = m_aircraft->fwRudder2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -127);
|
||||
|
||||
//ailerons
|
||||
channel = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (channel > -1) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, 127);
|
||||
|
||||
channel = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, -127);
|
||||
}
|
||||
// and set only the relevant channels:
|
||||
// Engine
|
||||
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
|
||||
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(127,ti);
|
||||
|
||||
//vtail
|
||||
channel = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
|
||||
if (channel > -1) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
value = (double)(m_aircraft->elevonSlider2->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, value);
|
||||
value = (double)(m_aircraft->elevonSlider1->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, value);
|
||||
|
||||
channel = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_SERVO);
|
||||
value = (double)(m_aircraft->elevonSlider2->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, value);
|
||||
value = (double)(m_aircraft->elevonSlider1->value()*1.27);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -value);
|
||||
}
|
||||
|
||||
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(-127,ti);
|
||||
}
|
||||
|
||||
// Now compute the VTail
|
||||
tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
|
||||
tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
|
||||
|
||||
obj->updated();
|
||||
|
||||
m_aircraft->fwStatusLabel->setText("Mixer generated");
|
||||
return true;
|
||||
}
|
||||
@ -604,7 +529,7 @@ bool ConfigVehicleTypeWidget::setupFrameVtail(QString airframeType)
|
||||
/**
|
||||
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::throwFixedWingChannelConfigError(QString airframeType)
|
||||
void ConfigFixedWingWidget::throwConfigError(QString airframeType)
|
||||
{
|
||||
//Initialize configuration error flag
|
||||
bool error=false;
|
||||
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configairframetwidget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief Airframe configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CONFIGFIXEDWINGWIDGET_H
|
||||
#define CONFIGFIXEDWINGWIDGET_H
|
||||
|
||||
#include "ui_airframe.h"
|
||||
#include "../uavobjectwidgetutils/configtaskwidget.h"
|
||||
#include "extensionsystem/pluginmanager.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
#include "uavtalk/telemetrymanager.h"
|
||||
#include <QtGui/QWidget>
|
||||
#include <QList>
|
||||
#include <QItemDelegate>
|
||||
|
||||
class Ui_Widget;
|
||||
|
||||
class ConfigFixedWingWidget: public VehicleConfig
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfigFixedWingWidget(Ui_AircraftWidget *aircraft = 0, QWidget *parent = 0);
|
||||
~ConfigFixedWingWidget();
|
||||
|
||||
friend class ConfigVehicleTypeWidget;
|
||||
|
||||
private:
|
||||
Ui_AircraftWidget *m_aircraft;
|
||||
|
||||
bool setupFrameFixedWing(QString airframeType);
|
||||
bool setupFrameElevon(QString airframeType);
|
||||
bool setupFrameVtail(QString airframeType);
|
||||
|
||||
virtual void ResetActuators(GUIConfigDataUnion* configData);
|
||||
virtual QStringList getChannelDescriptions();
|
||||
|
||||
private slots:
|
||||
virtual void setupUI(QString airframeType);
|
||||
virtual void refreshWidgetsValues(QString frameType);
|
||||
virtual QString updateConfigObjectsFromWidgets();
|
||||
virtual void throwConfigError(QString airframeType);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIGFIXEDWINGWIDGET_H
|
@ -24,7 +24,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
//#include "configgroundvehiclewidget.h"
|
||||
#include "configgroundvehiclewidget.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
#include "mixersettings.h"
|
||||
|
||||
@ -40,18 +40,35 @@
|
||||
|
||||
#include "mixersettings.h"
|
||||
#include "systemsettings.h"
|
||||
#include "actuatorsettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
|
||||
|
||||
/**
|
||||
Helper function to setup the UI
|
||||
Constructor
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType)
|
||||
ConfigGroundVehicleWidget::ConfigGroundVehicleWidget(Ui_AircraftWidget *aircraft, QWidget *parent) : VehicleConfig(parent)
|
||||
{
|
||||
m_aircraft = aircraft;
|
||||
}
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
ConfigGroundVehicleWidget::~ConfigGroundVehicleWidget()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
Virtual function to setup the UI
|
||||
*/
|
||||
void ConfigGroundVehicleWidget::setupUI(QString frameType)
|
||||
{
|
||||
m_aircraft->differentialSteeringMixBox->setHidden(true);
|
||||
//STILL NEEDS WORK
|
||||
// Setup the UI
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Ground"));
|
||||
setComboCurrentIndex(m_aircraft->aircraftType, m_aircraft->aircraftType->findText("Ground"));
|
||||
|
||||
m_aircraft->gvEngineChannelBox->setEnabled(false);
|
||||
m_aircraft->gvEngineLabel->setEnabled(false);
|
||||
@ -64,7 +81,7 @@ void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType)
|
||||
m_aircraft->gvAileron2Label->setEnabled(false);
|
||||
|
||||
if (frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)"){ //Tank
|
||||
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Differential (tank)"));
|
||||
setComboCurrentIndex(m_aircraft->groundVehicleType, m_aircraft->groundVehicleType->findText("Differential (tank)"));
|
||||
m_aircraft->gvMotor1ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvMotor1Label->setEnabled(true);
|
||||
|
||||
@ -89,7 +106,7 @@ void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType)
|
||||
|
||||
}
|
||||
else if (frameType == "GroundVehicleMotorcycle" || frameType == "Motorcycle"){ //Motorcycle
|
||||
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Motorcycle"));
|
||||
setComboCurrentIndex(m_aircraft->groundVehicleType, m_aircraft->groundVehicleType->findText("Motorcycle"));
|
||||
m_aircraft->gvMotor1ChannelBox->setEnabled(false);
|
||||
m_aircraft->gvMotor1Label->setEnabled(false);
|
||||
|
||||
@ -113,7 +130,7 @@ void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType)
|
||||
m_aircraft->gvThrottleCurve2GroupBox->setTitle("Rear throttle curve");
|
||||
}
|
||||
else {//Car
|
||||
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Turnable (car)"));
|
||||
setComboCurrentIndex(m_aircraft->groundVehicleType, m_aircraft->groundVehicleType->findText("Turnable (car)"));
|
||||
|
||||
m_aircraft->gvMotor1ChannelBox->setEnabled(true);
|
||||
m_aircraft->gvMotor1Label->setEnabled(true);
|
||||
@ -137,12 +154,46 @@ void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType)
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigGroundVehicleWidget::ResetActuators(GUIConfigDataUnion* configData)
|
||||
{
|
||||
configData->ground.GroundVehicleSteering1 = 0;
|
||||
configData->ground.GroundVehicleSteering2 = 0;
|
||||
configData->ground.GroundVehicleThrottle1 = 0;
|
||||
configData->ground.GroundVehicleThrottle2 = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to update the UI widget objects
|
||||
Virtual function to update the UI widget objects
|
||||
*/
|
||||
QString ConfigVehicleTypeWidget::updateGroundVehicleObjectsFromWidgets()
|
||||
QString ConfigGroundVehicleWidget::updateConfigObjectsFromWidgets()
|
||||
{
|
||||
QString airframeType = "GroundVehicleCar";
|
||||
|
||||
@ -176,56 +227,29 @@ QString ConfigVehicleTypeWidget::updateGroundVehicleObjectsFromWidgets()
|
||||
airframeType = "GroundVehicleMotorcycle";
|
||||
setupGroundVehicleMotorcycle(airframeType);
|
||||
}
|
||||
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to refresh the UI widget values
|
||||
Virtual function to refresh the UI widget values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshGroundVehicleWidgetsValues(QString frameType)
|
||||
void ConfigGroundVehicleWidget::refreshWidgetsValues(QString frameType)
|
||||
{
|
||||
|
||||
UAVDataObject* obj;
|
||||
UAVObjectField *field;
|
||||
|
||||
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
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField(QString("FixedWingThrottle"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvEngineChannelBox->setCurrentIndex(m_aircraft->gvEngineChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvAileron1ChannelBox->setCurrentIndex(m_aircraft->gvAileron1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("FixedWingRoll2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvAileron2ChannelBox->setCurrentIndex(m_aircraft->gvAileron2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleThrottle1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvMotor1ChannelBox->setCurrentIndex(m_aircraft->gvMotor1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleThrottle2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvMotor2ChannelBox->setCurrentIndex(m_aircraft->gvMotor2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleSteering1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvSteering1ChannelBox->setCurrentIndex(m_aircraft->gvSteering1ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
field = obj->getField(QString("GroundVehicleSteering2"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->gvSteering2ChannelBox->setCurrentIndex(m_aircraft->gvSteering2ChannelBox->findText(field->getValue().toString()));
|
||||
|
||||
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 == "GroundVehicleDifferential") {
|
||||
//CURRENTLY BROKEN UNTIL WE DECIDE HOW DIFFERENTIAL SHOULD BEHAVE
|
||||
// If the vehicle type is "differential", restore the slider setting
|
||||
@ -233,14 +257,11 @@ void ConfigVehicleTypeWidget::refreshGroundVehicleWidgetsValues(QString frameTyp
|
||||
// Find the channel number for Motor1
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
|
||||
field = obj->getField(mixerVectors.at(chMixerNumber));
|
||||
int ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
|
||||
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
|
||||
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(obj,channel,VehicleConfig::MIXERVECTOR_ROLL)*100);
|
||||
m_aircraft->differentialSteeringSlider2->setValue(getMixerVectorValue(obj,channel,VehicleConfig::MIXERVECTOR_PITCH)*100);
|
||||
}
|
||||
}
|
||||
if (frameType == "GroundVehicleMotorcycle") {
|
||||
@ -260,119 +281,62 @@ void ConfigVehicleTypeWidget::refreshGroundVehicleWidgetsValues(QString frameTyp
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Setup balancing ground vehicle.
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupGroundVehicleMotorcycle(QString airframeType){
|
||||
bool ConfigGroundVehicleWidget::setupGroundVehicleMotorcycle(QString airframeType){
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwGroundVehicleChannelConfigError(airframeType);
|
||||
throwConfigError(airframeType);
|
||||
|
||||
// - Motor, steering, and balance
|
||||
if (m_aircraft->gvMotor1ChannelBox->currentText() == "None" ||
|
||||
if (m_aircraft->gvMotor2ChannelBox->currentText() == "None" ||
|
||||
(m_aircraft->gvSteering1ChannelBox->currentText() == "None" ||
|
||||
m_aircraft->gvSteering2ChannelBox->currentText() == "None") )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Left motor
|
||||
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
|
||||
|
||||
// Right motor
|
||||
field = obj->getField("GroundVehicleThrottle2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
|
||||
int tmpVal, ti;
|
||||
|
||||
// Disable all output channels
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
|
||||
//Disable output channel
|
||||
field->setValue("Disabled");
|
||||
|
||||
}
|
||||
|
||||
// Set all mixer values to zero
|
||||
foreach(QString mixer, mixerVectors) {
|
||||
field = obj->getField(mixer);
|
||||
resetField(field);
|
||||
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(0, ti);
|
||||
}
|
||||
|
||||
// Motor
|
||||
// Setup motor
|
||||
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward
|
||||
field->setValue(127, ti);
|
||||
|
||||
//Steering
|
||||
// Setup steering
|
||||
tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set steering response to roll
|
||||
field->setValue(-127, ti);
|
||||
ti = field->getElementNames().indexOf("Roll"); //Set steering response to roll
|
||||
field->setValue(-127, ti);
|
||||
|
||||
//Balancing
|
||||
// Setup balancing servo
|
||||
tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set balance response to yaw
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Roll"); //Set balance response to roll
|
||||
field->setValue(127, ti);
|
||||
// Now setup the channels:
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
ResetActuators(&config);
|
||||
|
||||
config.ground.GroundVehicleThrottle1 = m_aircraft->gvMotor1ChannelBox->currentIndex();
|
||||
config.ground.GroundVehicleThrottle2 = m_aircraft->gvMotor2ChannelBox->currentIndex();
|
||||
|
||||
SetConfigData(config);
|
||||
|
||||
obj->updated();
|
||||
|
||||
//Output success message
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
int channel;
|
||||
//disable all
|
||||
for (channel=0; channel<VehicleConfig::CHANNEL_NUMELEM; channel++) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_DISABLED);
|
||||
resetMixerVector(mixer, channel);
|
||||
}
|
||||
|
||||
//motor
|
||||
channel = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
|
||||
//steering
|
||||
channel = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, -127);
|
||||
|
||||
//balance
|
||||
channel = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, 127);
|
||||
|
||||
m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
|
||||
return true;
|
||||
@ -385,10 +349,10 @@ bool ConfigVehicleTypeWidget::setupGroundVehicleMotorcycle(QString airframeType)
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupGroundVehicleDifferential(QString airframeType){
|
||||
bool ConfigGroundVehicleWidget::setupGroundVehicleDifferential(QString airframeType){
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwGroundVehicleChannelConfigError(airframeType);
|
||||
throwConfigError(airframeType);
|
||||
|
||||
// - Left and right steering
|
||||
if ( m_aircraft->gvMotor2ChannelBox->currentText() == "None" ||
|
||||
@ -397,86 +361,37 @@ bool ConfigVehicleTypeWidget::setupGroundVehicleDifferential(QString airframeTyp
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Now setup the channels:
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
ResetActuators(&config);
|
||||
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
config.ground.GroundVehicleThrottle1 = m_aircraft->gvMotor1ChannelBox->currentIndex();
|
||||
config.ground.GroundVehicleThrottle2 = m_aircraft->gvMotor2ChannelBox->currentIndex();
|
||||
|
||||
SetConfigData((config));
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Left motor
|
||||
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
|
||||
|
||||
// Right motor
|
||||
field = obj->getField("GroundVehicleThrottle2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
|
||||
int tmpVal, ti;
|
||||
|
||||
// Disable all output channels
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
|
||||
//Disable output channel
|
||||
field->setValue("Disabled");
|
||||
|
||||
}
|
||||
|
||||
// Set all mixer values to zero
|
||||
foreach(QString mixer, mixerVectors) {
|
||||
field = obj->getField(mixer);
|
||||
resetField(field);
|
||||
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(0, ti);
|
||||
}
|
||||
|
||||
// Motor
|
||||
// Setup left motor
|
||||
tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn right with increasing throttle
|
||||
field->setValue(127, ti);
|
||||
|
||||
// Setup right motor
|
||||
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo"); //Set motor mixer type to Servo
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2"); //Set motor to full forward
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn left with increasing throttle
|
||||
field->setValue(-127, ti);
|
||||
|
||||
obj->updated();
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
int channel;
|
||||
//disable all
|
||||
for (channel=0; channel<VehicleConfig::CHANNEL_NUMELEM; channel++) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_DISABLED);
|
||||
resetMixerVector(mixer, channel);
|
||||
}
|
||||
|
||||
//left motor
|
||||
channel = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
|
||||
//right motor
|
||||
channel = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE2, 127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -127);
|
||||
|
||||
//Output success message
|
||||
m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
@ -492,11 +407,11 @@ bool ConfigVehicleTypeWidget::setupGroundVehicleDifferential(QString airframeTyp
|
||||
|
||||
Returns False if impossible to create the mixer.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupGroundVehicleCar(QString airframeType)
|
||||
bool ConfigGroundVehicleWidget::setupGroundVehicleCar(QString airframeType)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwGroundVehicleChannelConfigError(airframeType);
|
||||
throwConfigError(airframeType);
|
||||
|
||||
// - At least one motor and one steering servo
|
||||
if ((m_aircraft->gvMotor1ChannelBox->currentText() == "None" &&
|
||||
@ -506,147 +421,43 @@ bool ConfigVehicleTypeWidget::setupGroundVehicleCar(QString airframeType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// else{
|
||||
// // m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText());
|
||||
// delete htmlText;
|
||||
//
|
||||
// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags.
|
||||
// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText());
|
||||
// }
|
||||
|
||||
// Now setup the channels:
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
ResetActuators(&config);
|
||||
|
||||
// Now setup the channels:
|
||||
resetActuators();
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
// Front motor
|
||||
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
|
||||
|
||||
// Rear motor
|
||||
field = obj->getField("GroundVehicleThrottle2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
|
||||
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();
|
||||
|
||||
// // Aileron
|
||||
// field = obj->getField("FixedWingRoll1");
|
||||
// Q_ASSERT(field);
|
||||
// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
|
||||
//
|
||||
// field = obj->getField("FixedWingRoll2");
|
||||
// Q_ASSERT(field);
|
||||
// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
|
||||
SetConfigData(config);
|
||||
|
||||
// Front steering
|
||||
field = obj->getField("GroundVehicleSteering1");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvSteering1ChannelBox->currentText());
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
// Rear steering
|
||||
field = obj->getField("GroundVehicleSteering2");
|
||||
Q_ASSERT(field);
|
||||
field->setValue(m_aircraft->gvSteering2ChannelBox->currentText());
|
||||
|
||||
obj->updated();
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
// ... and compute the matrix:
|
||||
// In order to make code a bit nicer, we assume:
|
||||
// - Channel dropdowns start with 'None', then 0 to 7
|
||||
|
||||
// 1. Assign the servo/motor/none for each channel
|
||||
|
||||
int tmpVal, ti;
|
||||
|
||||
// Disable all output channels
|
||||
foreach(QString mixer, mixerTypes) {
|
||||
field = obj->getField(mixer);
|
||||
Q_ASSERT(field);
|
||||
|
||||
//Disable output channel
|
||||
field->setValue("Disabled");
|
||||
|
||||
}
|
||||
|
||||
// Set all mixer values to zero
|
||||
foreach(QString mixer, mixerVectors) {
|
||||
field = obj->getField(mixer);
|
||||
resetField(field);
|
||||
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(0, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(0, ti);
|
||||
}
|
||||
|
||||
// Steering
|
||||
// Only set front steering if it is defined
|
||||
tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if steering is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127, ti);
|
||||
} // Else: we have no front steering. We're fine with it as long as we have rear steering
|
||||
|
||||
// Only set rear steering if it is defined
|
||||
tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
|
||||
// tmpVal will be -1 if steering is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(-127, ti);
|
||||
} // Else: we have no rear steering. We're fine with it as long as we have front steering
|
||||
|
||||
// Motor
|
||||
// Only set front motor if it is defined
|
||||
tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
}
|
||||
|
||||
// Only set rear motor if it is defined
|
||||
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
field->setValue(127, ti);
|
||||
int channel;
|
||||
//disable all
|
||||
for (channel=0; channel<VehicleConfig::CHANNEL_NUMELEM; channel++) {
|
||||
setMixerType(mixer,channel,VehicleConfig::MIXERTYPE_DISABLED);
|
||||
resetMixerVector(mixer, channel);
|
||||
}
|
||||
|
||||
obj->updated();
|
||||
|
||||
channel = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
|
||||
channel = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, -127);
|
||||
|
||||
channel = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);
|
||||
|
||||
channel = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
|
||||
setMixerType(mixer,channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE2, 127);
|
||||
|
||||
//Output success message
|
||||
m_aircraft->gvStatusLabel->setText("Mixer generated");
|
||||
@ -657,7 +468,7 @@ bool ConfigVehicleTypeWidget::setupGroundVehicleCar(QString airframeType)
|
||||
/**
|
||||
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::throwGroundVehicleChannelConfigError(QString airframeType)
|
||||
void ConfigGroundVehicleWidget::throwConfigError(QString airframeType)
|
||||
{
|
||||
//Initialize configuration error flag
|
||||
bool error=false;
|
||||
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configairframetwidget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief Airframe configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CONFIGGROUNDVEHICLEWIDGET_H
|
||||
#define CONFIGGROUNDVEHICLEWIDGET_H
|
||||
|
||||
#include "ui_airframe.h"
|
||||
#include "../uavobjectwidgetutils/configtaskwidget.h"
|
||||
#include "extensionsystem/pluginmanager.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
#include "uavtalk/telemetrymanager.h"
|
||||
#include <QtGui/QWidget>
|
||||
#include <QList>
|
||||
#include <QItemDelegate>
|
||||
|
||||
class Ui_Widget;
|
||||
|
||||
class ConfigGroundVehicleWidget: public VehicleConfig
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfigGroundVehicleWidget(Ui_AircraftWidget *aircraft = 0, QWidget *parent = 0);
|
||||
~ConfigGroundVehicleWidget();
|
||||
|
||||
friend class ConfigVehicleTypeWidget;
|
||||
|
||||
private:
|
||||
Ui_AircraftWidget *m_aircraft;
|
||||
|
||||
bool setupGroundVehicleCar(QString airframeType);
|
||||
bool setupGroundVehicleDifferential(QString airframeType);
|
||||
bool setupGroundVehicleMotorcycle(QString airframeType);
|
||||
|
||||
virtual void ResetActuators(GUIConfigDataUnion* configData);
|
||||
virtual QStringList getChannelDescriptions();
|
||||
|
||||
private slots:
|
||||
virtual void setupUI(QString airframeType);
|
||||
virtual void refreshWidgetsValues(QString frameType);
|
||||
virtual QString updateConfigObjectsFromWidgets();
|
||||
virtual void throwConfigError(QString airframeType);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIGGROUNDVEHICLEWIDGET_H
|
@ -24,8 +24,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
//#include "configmultirotorwidget.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
#include "configmultirotorwidget.h"
|
||||
#include "mixersettings.h"
|
||||
|
||||
#include <QDebug>
|
||||
@ -34,200 +33,192 @@
|
||||
#include <QtGui/QTextEdit>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtGui/QComboBox>
|
||||
#include <QBrush>
|
||||
#include <math.h>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "mixersettings.h"
|
||||
#include "systemsettings.h"
|
||||
#include "actuatorsettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
|
||||
//#define Pi 3.14159265358979323846
|
||||
|
||||
|
||||
/**
|
||||
Helper function to setup the UI
|
||||
Constructor
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupMultiRotorUI(QString frameType)
|
||||
ConfigMultiRotorWidget::ConfigMultiRotorWidget(Ui_AircraftWidget *aircraft, QWidget *parent) : VehicleConfig(parent)
|
||||
{
|
||||
if (frameType == "Tri" || frameType == "Tricopter Y") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y"));
|
||||
m_aircraft = aircraft;
|
||||
}
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
ConfigMultiRotorWidget::~ConfigMultiRotorWidget()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
void ConfigMultiRotorWidget::setupUI(QString frameType)
|
||||
{
|
||||
Q_ASSERT(m_aircraft);
|
||||
Q_ASSERT(uiowner);
|
||||
Q_ASSERT(quad);
|
||||
|
||||
int i;
|
||||
|
||||
// set aircraftType to Multirotor, disable triyaw channel
|
||||
setComboCurrentIndex(m_aircraft->aircraftType, m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
|
||||
// disable all motor channel boxes
|
||||
for (i=1; i <=8; i++) {
|
||||
// do it manually so we can turn off any error decorations
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(uiowner, "multiMotorChannelBox" + QString::number(i));
|
||||
if (combobox) {
|
||||
combobox->setEnabled(false);
|
||||
combobox->setItemData(0, 0, Qt::DecorationRole);
|
||||
}
|
||||
}
|
||||
|
||||
if (frameType == "Tri" || frameType == "Tricopter Y") {
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Tricopter Y"));
|
||||
quad->setElementId("tri");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=3; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=4; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
for (i=1; i <=3; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(true);
|
||||
} else if (frameType == "QuadX" || frameType == "Quad X") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X"));
|
||||
m_aircraft->triYawChannelBox->setEnabled(true);
|
||||
}
|
||||
else if (frameType == "QuadX" || frameType == "Quad X") {
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Quad X"));
|
||||
quad->setElementId("quad-X");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=4; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (i=1; i <=4; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=5; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
} else if (frameType == "QuadP" || frameType == "Quad +") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +"));
|
||||
}
|
||||
else if (frameType == "QuadP" || frameType == "Quad +") {
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Quad +"));
|
||||
quad->setElementId("quad-plus");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=4; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=5; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
for (i=1; i <=4; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(100);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
} else if (frameType == "Hexa" || frameType == "Hexacopter") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter"));
|
||||
}
|
||||
else if (frameType == "Hexa" || frameType == "Hexacopter")
|
||||
{
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Hexacopter"));
|
||||
quad->setElementId("quad-hexa");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=6; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (i=1; i <=6; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=7; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(33);
|
||||
m_aircraft->mrYawMixLevel->setValue(33);
|
||||
} else if (frameType == "HexaX" || frameType == "Hexacopter X" ) {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X"));
|
||||
}
|
||||
else if (frameType == "HexaX" || frameType == "Hexacopter X" ) {
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Hexacopter X"));
|
||||
quad->setElementId("quad-hexa-H");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=6; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (i=1; i <=6; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=7; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
|
||||
m_aircraft->mrRollMixLevel->setValue(33);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(33);
|
||||
|
||||
} else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6"));
|
||||
}
|
||||
else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6")
|
||||
{
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Hexacopter Y6"));
|
||||
quad->setElementId("hexa-coax");
|
||||
|
||||
//Enable all necessary motor channel boxes...
|
||||
for (int i=1; i <=6; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (i=1; i <=6; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
//and grey out all unused motor channel boxes
|
||||
for (int i=7; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(false);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(66);
|
||||
|
||||
} else if (frameType == "Octo" || frameType == "Octocopter") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter"));
|
||||
}
|
||||
else if (frameType == "Octo" || frameType == "Octocopter")
|
||||
{
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Octocopter"));
|
||||
quad->setElementId("quad-octo");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (i=1; i <=8; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
|
||||
m_aircraft->mrRollMixLevel->setValue(33);
|
||||
m_aircraft->mrPitchMixLevel->setValue(33);
|
||||
m_aircraft->mrYawMixLevel->setValue(25);
|
||||
} else if (frameType == "OctoV" || frameType == "Octocopter V") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V"));
|
||||
}
|
||||
else if (frameType == "OctoV" || frameType == "Octocopter V")
|
||||
{
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Octocopter V"));
|
||||
quad->setElementId("quad-octo-v");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (i=1; i <=8; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(25);
|
||||
m_aircraft->mrPitchMixLevel->setValue(25);
|
||||
m_aircraft->mrYawMixLevel->setValue(25);
|
||||
|
||||
} else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +"));
|
||||
}
|
||||
else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +")
|
||||
{
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Octo Coax +"));
|
||||
quad->setElementId("octo-coax-P");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (int i=1; i <=8; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(100);
|
||||
m_aircraft->mrPitchMixLevel->setValue(100);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
|
||||
} else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X"));
|
||||
}
|
||||
else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X")
|
||||
{
|
||||
setComboCurrentIndex( m_aircraft->multirotorFrameType, m_aircraft->multirotorFrameType->findText("Octo Coax X"));
|
||||
quad->setElementId("octo-coax-X");
|
||||
|
||||
//Enable all necessary motor channel boxes
|
||||
for (int i=1; i <=8; i++) {
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
|
||||
combobox->setEnabled(true);
|
||||
for (int i=1; i <=8; i++) {
|
||||
enableComboBox(uiowner, QString("multiMotorChannelBox%0").arg(i), true);
|
||||
}
|
||||
|
||||
m_aircraft->triYawChannelBox->setEnabled(false);
|
||||
m_aircraft->mrRollMixLevel->setValue(50);
|
||||
m_aircraft->mrPitchMixLevel->setValue(50);
|
||||
m_aircraft->mrYawMixLevel->setValue(50);
|
||||
@ -235,12 +226,61 @@ void ConfigVehicleTypeWidget::setupMultiRotorUI(QString frameType)
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigMultiRotorWidget::ResetActuators(GUIConfigDataUnion* configData)
|
||||
{
|
||||
configData->multi.VTOLMotorN = 0;
|
||||
configData->multi.VTOLMotorNE = 0;
|
||||
configData->multi.VTOLMotorE = 0;
|
||||
configData->multi.VTOLMotorSE = 0;
|
||||
configData->multi.VTOLMotorS = 0;
|
||||
configData->multi.VTOLMotorSW = 0;
|
||||
configData->multi.VTOLMotorW = 0;
|
||||
configData->multi.VTOLMotorNW = 0;
|
||||
configData->multi.TRIYaw = 0;
|
||||
}
|
||||
|
||||
QStringList ConfigMultiRotorWidget::getChannelDescriptions()
|
||||
{
|
||||
int i;
|
||||
QStringList channelDesc;
|
||||
|
||||
// init a channel_numelem list of channel desc defaults
|
||||
for (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");
|
||||
|
||||
return channelDesc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Helper function to update the UI widget objects
|
||||
*/
|
||||
QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
QString ConfigMultiRotorWidget::updateConfigObjectsFromWidgets()
|
||||
{
|
||||
QString airframeType;
|
||||
QList<QString> motorList;
|
||||
@ -279,7 +319,7 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
airframeType = "HexaCoax";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(6);
|
||||
throwConfigError(6);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
@ -313,7 +353,7 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
airframeType = "Octo";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
throwConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
@ -348,7 +388,7 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
airframeType = "OctoV";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
throwConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
@ -384,7 +424,7 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
airframeType = "OctoCoaxP";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
throwConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
@ -419,7 +459,7 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
airframeType = "OctoCoaxX";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(8);
|
||||
throwConfigError(8);
|
||||
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
@ -454,7 +494,7 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
airframeType = "Tri";
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(3);
|
||||
throwConfigError(3);
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
|
||||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ) {
|
||||
@ -467,10 +507,11 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
}
|
||||
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
|
||||
setupMotors(motorList);
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
field = obj->getField("FixedWingYaw1");
|
||||
field->setValue(m_aircraft->triYawChannelBox->currentText());
|
||||
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
config.multi.TRIYaw = m_aircraft->triYawChannelBox->currentIndex();
|
||||
SetConfigData(config);
|
||||
|
||||
|
||||
// Motor 1 to 6, Y6 Layout:
|
||||
// pitch roll yaw
|
||||
@ -485,21 +526,20 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
{ 0, 0, 0}
|
||||
};
|
||||
setupMultiRotorMixer(mixer);
|
||||
|
||||
int tmpVal = m_aircraft->triYawChannelBox->currentIndex()-1;
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
field = obj->getField(mixerTypes.at(tmpVal));
|
||||
field->setValue("Servo");
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(127,ti);
|
||||
|
||||
//tell the mixer about tricopter yaw channel
|
||||
UAVDataObject* mixerObj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixerObj);
|
||||
|
||||
int channel = m_aircraft->triYawChannelBox->currentIndex()-1;
|
||||
if (channel > -1){
|
||||
setMixerType(mixerObj, channel, VehicleConfig::MIXERTYPE_SERVO);
|
||||
setMixerVectorValue(mixerObj, channel, VehicleConfig::MIXERVECTOR_YAW, 127);
|
||||
}
|
||||
|
||||
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
|
||||
|
||||
}
|
||||
// Now reflect those settings in the "Custom" panel as well
|
||||
updateCustomAirframeUI();
|
||||
}
|
||||
|
||||
return airframeType;
|
||||
}
|
||||
@ -509,342 +549,253 @@ QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
|
||||
/**
|
||||
Helper function to refresh the UI widget values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshMultiRotorWidgetsValues(QString frameType)
|
||||
void ConfigMultiRotorWidget::refreshWidgetsValues(QString frameType)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Retrieve settings
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field;
|
||||
|
||||
int channel;
|
||||
double value;
|
||||
|
||||
GUIConfigDataUnion config = GetConfigData();
|
||||
multiGUISettingsStruct multi = config.multi;
|
||||
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
if (frameType == "QuadP") {
|
||||
// Motors 1/2/3/4 are: N / E / S / W
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// 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.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = (1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = -field->getDouble(i)/1.27;
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
|
||||
channel = m_aircraft->multiMotorChannelBox1->currentIndex() - 1;
|
||||
if (channel > -1)
|
||||
{
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( value/1.27 );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( 1-value/1.27 );
|
||||
|
||||
channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( -value/1.27);
|
||||
|
||||
}
|
||||
} else if (frameType == "QuadX") {
|
||||
// Motors 1/2/3/4 are: NW / NE / SE / SW
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// 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.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = 1-field->getDouble(i)/1.27;
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = field->getDouble(i)/1.27;
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
// 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(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( value/1.27 );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( 1-value/1.27 );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( value/1.27);
|
||||
|
||||
}
|
||||
|
||||
} else if (frameType == "Hexa") {
|
||||
// Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// 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.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
if(tmpVal>-1)
|
||||
{
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
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(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( floor(value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( floor(-value/1.27) );
|
||||
|
||||
//change channels
|
||||
channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( floor(1-value/1.27) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else if (frameType == "HexaX") {
|
||||
// Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// 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.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(1-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
// 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(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( floor(value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( floor(-value/1.27) );
|
||||
|
||||
channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( floor(1-value/1.27) );
|
||||
}
|
||||
} else if (frameType == "HexaCoax") {
|
||||
// Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// 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.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(2*field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
// 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(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( value/1.27 );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( value/1.27 );
|
||||
|
||||
channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( value/1.27);
|
||||
}
|
||||
} else if (frameType == "Octo" || frameType == "OctoV" ||
|
||||
frameType == "OctoCoaxP") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// 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.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
if (frameType == "Octo") {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
} else if (frameType == "OctoV") {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Yaw");
|
||||
double val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Pitch");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
|
||||
} else if (frameType == "OctoCoaxP") {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
tmpVal = m_aircraft->multiMotorChannelBox3->currentIndex()-1;
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
|
||||
}
|
||||
}
|
||||
// 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 == "Octo") {
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( floor(value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( floor(-value/1.27) );
|
||||
|
||||
//change channels
|
||||
channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( floor(-value/1.27) );
|
||||
}
|
||||
else if (frameType == "OctoV") {
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( floor(value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( floor(-value/1.27) );
|
||||
|
||||
//change channels
|
||||
channel = m_aircraft->multiMotorChannelBox2->currentIndex() - 1;
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( floor(-value/1.27) );
|
||||
}
|
||||
else if (frameType == "OctoCoaxP") {
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( floor(value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( floor(-value/1.27) );
|
||||
|
||||
//change channels
|
||||
channel = m_aircraft->multiMotorChannelBox3->currentIndex() - 1;
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( floor(-value/1.27) );
|
||||
}
|
||||
|
||||
}
|
||||
} else if (frameType == "OctoCoaxX") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorN"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorSW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
|
||||
|
||||
// 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.
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Yaw");
|
||||
val = floor(-field->getDouble(i)/1.27);
|
||||
m_aircraft->mrYawMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
// 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(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( floor(value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW);
|
||||
m_aircraft->mrYawMixLevel->setValue( floor(-value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( floor(value/1.27) );
|
||||
}
|
||||
} else if (frameType == "Tri") {
|
||||
// Motors 1 to 8 are N / NE / E / etc
|
||||
field = obj->getField(QString("VTOLMotorNW"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorNE"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("VTOLMotorS"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
field = obj->getField(QString("FixedWingYaw1"));
|
||||
Q_ASSERT(field);
|
||||
m_aircraft->triYawChannelBox->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
|
||||
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
|
||||
// tmpVal will be -1 if value is set to "None"
|
||||
if (tmpVal > -1) {
|
||||
field = obj->getField(mixerVectors.at(tmpVal));
|
||||
int i = field->getElementNames().indexOf("Pitch");
|
||||
double val = floor(2*field->getDouble(i)/1.27);
|
||||
m_aircraft->mrPitchMixLevel->setValue(val);
|
||||
i = field->getElementNames().indexOf("Roll");
|
||||
val = floor(field->getDouble(i)/1.27);
|
||||
m_aircraft->mrRollMixLevel->setValue(val);
|
||||
}
|
||||
// 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(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH);
|
||||
m_aircraft->mrPitchMixLevel->setValue( floor(2*value/1.27) );
|
||||
|
||||
value = getMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL);
|
||||
m_aircraft->mrRollMixLevel->setValue( floor(value/1.27) );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -853,27 +804,20 @@ void ConfigVehicleTypeWidget::refreshMultiRotorWidgetsValues(QString frameType)
|
||||
/**
|
||||
Helper function: setupQuadMotor
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
|
||||
void ConfigMultiRotorWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
|
||||
{
|
||||
qDebug()<<QString("Setup quad motor channel=%0 pitch=%1 roll=%2 yaw=%3").arg(channel).arg(pitch).arg(roll).arg(yaw);
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field = obj->getField(mixerTypes.at(channel));
|
||||
field->setValue("Motor");
|
||||
field = obj->getField(mixerVectors.at(channel));
|
||||
// First of all reset the vector
|
||||
resetField(field);
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
field->setValue(127, ti);
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
field->setValue(roll*127,ti);
|
||||
qDebug()<<"Set roll="<<roll*127;
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
field->setValue(pitch*127,ti);
|
||||
qDebug()<<"Set pitch="<<pitch*127;
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(yaw*127,ti);
|
||||
qDebug()<<"Set yaw="<<yaw*127;
|
||||
|
||||
UAVDataObject* mixer = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
setMixerType(mixer, channel, VehicleConfig::MIXERTYPE_MOTOR);
|
||||
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE2, 0);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, roll*127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, pitch*127);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, yaw*127);
|
||||
}
|
||||
|
||||
|
||||
@ -881,21 +825,42 @@ void ConfigVehicleTypeWidget::setupQuadMotor(int channel, double pitch, double r
|
||||
/**
|
||||
Helper function: setup motors. Takes a list of channel names in input.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupMotors(QList<QString> motorList)
|
||||
void ConfigMultiRotorWidget::setupMotors(QList<QString> motorList)
|
||||
{
|
||||
resetActuators();
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
UAVObjectField *field;
|
||||
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) {
|
||||
field = obj->getField(motor);
|
||||
field->setValue(mmList.takeFirst()->currentText());
|
||||
|
||||
index = mmList.takeFirst()->currentIndex();
|
||||
|
||||
//qDebug()<<QString("Setup motor: %0 = %1").arg(motor).arg(index);
|
||||
|
||||
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;
|
||||
}
|
||||
//obj->updated(); // Save...
|
||||
SetConfigData(configData);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -903,12 +868,12 @@ void ConfigVehicleTypeWidget::setupMotors(QList<QString> motorList)
|
||||
/**
|
||||
Set up a Quad-X or Quad-P mixer
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupQuad(bool pLayout)
|
||||
bool ConfigMultiRotorWidget::setupQuad(bool pLayout)
|
||||
{
|
||||
// Check coherence:
|
||||
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(4);
|
||||
throwConfigError(4);
|
||||
|
||||
// - Four engines have to be defined
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
@ -979,11 +944,11 @@ bool ConfigVehicleTypeWidget::setupQuad(bool pLayout)
|
||||
/**
|
||||
Set up a Hexa-X or Hexa-P mixer
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupHexa(bool pLayout)
|
||||
bool ConfigMultiRotorWidget::setupHexa(bool pLayout)
|
||||
{
|
||||
// Check coherence:
|
||||
//Show any config errors in GUI
|
||||
throwMultiRotorChannelConfigError(6);
|
||||
throwConfigError(6);
|
||||
|
||||
// - Four engines have to be defined
|
||||
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
|
||||
@ -1060,7 +1025,7 @@ bool ConfigVehicleTypeWidget::setupHexa(bool pLayout)
|
||||
/**
|
||||
This function sets up the multirotor mixer values.
|
||||
*/
|
||||
bool ConfigVehicleTypeWidget::setupMultiRotorMixer(double mixerFactors[8][3])
|
||||
bool ConfigMultiRotorWidget::setupMultiRotorMixer(double mixerFactors[8][3])
|
||||
{
|
||||
qDebug()<<"Mixer factors";
|
||||
qDebug()<<mixerFactors[0][0]<<" "<<mixerFactors[0][1]<<" "<<mixerFactors[0][2];
|
||||
@ -1107,34 +1072,25 @@ bool ConfigVehicleTypeWidget::setupMultiRotorMixer(double mixerFactors[8][3])
|
||||
/**
|
||||
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::throwMultiRotorChannelConfigError(int numMotors)
|
||||
{
|
||||
void ConfigMultiRotorWidget::throwConfigError(int numMotors)
|
||||
{
|
||||
//Initialize configuration error flag
|
||||
bool error=false;
|
||||
|
||||
//Iterate through all instances of multiMotorChannelBox
|
||||
for (int i=0; i<numMotors; i++) {
|
||||
//Fine widgets with text "multiMotorChannelBox.x", where x is an integer
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i+1));
|
||||
if (combobox){ //if QLabel exists
|
||||
QLabel *label = qFindChild<QLabel*>(this, "MotorOutputLabel" + QString::number(i+1));
|
||||
if (combobox->currentText() == "None") {
|
||||
|
||||
// label->setText("<font color='red'>" + label->text() + "</font>");
|
||||
|
||||
QComboBox *combobox = qFindChild<QComboBox*>(uiowner, "multiMotorChannelBox" + QString::number(i+1));
|
||||
if (combobox){
|
||||
if (combobox->currentText() == "None") {
|
||||
int size = combobox->style()->pixelMetric(QStyle::PM_SmallIconSize);
|
||||
QPixmap pixmap(size,size);
|
||||
pixmap.fill(QColor("red"));
|
||||
combobox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
// combobox->setStyleSheet("QComboBox { color: red}");
|
||||
combobox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
|
||||
error=true;
|
||||
|
||||
}
|
||||
else {
|
||||
combobox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
// combobox->setStyleSheet("color: black;");
|
||||
// QTextEdit* htmlText=new QTextEdit(label->text()); // htmlText is any QString with html tags.
|
||||
// label->setText(htmlText->toPlainText());
|
||||
combobox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1143,4 +1099,6 @@ void ConfigVehicleTypeWidget::throwMultiRotorChannelConfigError(int numMotors)
|
||||
if (error){
|
||||
m_aircraft->mrStatusLabel->setText(QString("<font color='red'>ERROR: Assign all %1 motor channels</font>").arg(numMotors));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file configairframetwidget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief Airframe configuration panel
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef CONFIGMULTIROTORWIDGET_H
|
||||
#define CONFIGMULTIROTORWIDGET_H
|
||||
|
||||
#include "ui_airframe.h"
|
||||
#include "../uavobjectwidgetutils/configtaskwidget.h"
|
||||
|
||||
#include "extensionsystem/pluginmanager.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
#include "uavtalk/telemetrymanager.h"
|
||||
#include <QtGui/QWidget>
|
||||
#include <QList>
|
||||
#include <QItemDelegate>
|
||||
|
||||
class Ui_Widget;
|
||||
|
||||
class ConfigMultiRotorWidget: public VehicleConfig
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfigMultiRotorWidget(Ui_AircraftWidget *aircraft = 0, QWidget *parent = 0);
|
||||
~ConfigMultiRotorWidget();
|
||||
|
||||
friend class ConfigVehicleTypeWidget;
|
||||
|
||||
private:
|
||||
Ui_AircraftWidget *m_aircraft;
|
||||
|
||||
QWidget *uiowner;
|
||||
QGraphicsSvgItem *quad;
|
||||
|
||||
bool setupQuad(bool pLayout);
|
||||
bool setupHexa(bool pLayout);
|
||||
bool setupOcto();
|
||||
bool setupMultiRotorMixer(double mixerFactors[8][3]);
|
||||
void setupMotors(QList<QString> motorList);
|
||||
void setupQuadMotor(int channel, double roll, double pitch, double yaw);
|
||||
|
||||
virtual void ResetActuators(GUIConfigDataUnion* configData);
|
||||
virtual QStringList getChannelDescriptions();
|
||||
|
||||
private slots:
|
||||
virtual void setupUI(QString airframeType);
|
||||
virtual void refreshWidgetsValues(QString frameType);
|
||||
virtual QString updateConfigObjectsFromWidgets();
|
||||
void throwConfigError(int numMotors);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
signals:
|
||||
void configurationChanged();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIGMULTIROTORWIDGET_H
|
@ -0,0 +1,256 @@
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file vehicleconfig.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief bit storage of config ui settings
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "cfg_vehicletypes/vehicleconfig.h"
|
||||
#include "extensionsystem/pluginmanager.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
|
||||
#include "systemsettings.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
VehicleConfig::VehicleConfig(QWidget *parent) : ConfigTaskWidget(parent)
|
||||
{
|
||||
//Generate lists of mixerTypeNames, mixerVectorNames, channelNames
|
||||
channelNames << "None";
|
||||
for (int i = 0; i < (int)(VehicleConfig::CHANNEL_NUMELEM); i++) {
|
||||
mixerTypes << QString("Mixer%1Type").arg(i+1);
|
||||
mixerVectors << QString("Mixer%1Vector").arg(i+1);
|
||||
channelNames << QString("Channel%1").arg(i+1);
|
||||
}
|
||||
|
||||
// typedef enum { MIXERTYPE_DISABLED=0, MIXERTYPE_MOTOR=1, MIXERTYPE_SERVO=2,
|
||||
//MIXERTYPE_CAMERAROLL=3, MIXERTYPE_CAMERAPITCH=4, MIXERTYPE_CAMERAYAW=5,
|
||||
//MIXERTYPE_ACCESSORY0=6, MIXERTYPE_ACCESSORY1=7, MIXERTYPE_ACCESSORY2=8,
|
||||
//MIXERTYPE_ACCESSORY3=9, MIXERTYPE_ACCESSORY4=10, MIXERTYPE_ACCESSORY5=11 } MixerTypeElem;
|
||||
|
||||
mixerTypeDescriptions << "Disabled" << "Motor" << "Servo" << "CameraRoll" << "CameraPitch"
|
||||
<< "CameraYaw" << "Accessory0" << "Accessory1" << "Accessory2"
|
||||
<< "Accessory3" << "Accessory4" << "Accessory5";
|
||||
|
||||
// This is needed because new style tries to compact things as much as possible in grid
|
||||
// and on OSX the widget sizes of PushButtons is reported incorrectly:
|
||||
// https://bugreports.qt-project.org/browse/QTBUG-14591
|
||||
foreach( QPushButton * btn, findChildren<QPushButton*>() ) {
|
||||
btn->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
}
|
||||
}
|
||||
|
||||
VehicleConfig::~VehicleConfig()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
GUIConfigDataUnion VehicleConfig::GetConfigData() {
|
||||
|
||||
int i;
|
||||
GUIConfigDataUnion configData;
|
||||
|
||||
// get an instance of systemsettings
|
||||
SystemSettings * systemSettings = SystemSettings::GetInstance(getUAVObjectManager());
|
||||
Q_ASSERT(systemSettings);
|
||||
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
|
||||
|
||||
// copy systemsettings -> local configData
|
||||
for(i = 0; i < (int)(SystemSettings::GUICONFIGDATA_NUMELEM); i++)
|
||||
configData.UAVObject[i]=systemSettingsData.GUIConfigData[i];
|
||||
|
||||
// sanity check
|
||||
Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM ==
|
||||
(sizeof(configData.UAVObject) / sizeof(configData.UAVObject[0])));
|
||||
|
||||
return configData;
|
||||
}
|
||||
|
||||
void VehicleConfig::SetConfigData(GUIConfigDataUnion configData) {
|
||||
|
||||
int i;
|
||||
|
||||
// sanity check
|
||||
Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM ==
|
||||
(sizeof(configData.UAVObject) / sizeof(configData.UAVObject[0])));
|
||||
|
||||
// get an instance of systemsettings
|
||||
SystemSettings * systemSettings = SystemSettings::GetInstance(getUAVObjectManager());
|
||||
Q_ASSERT(systemSettings);
|
||||
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
|
||||
|
||||
// copy parameter configData -> systemsettings
|
||||
for (i = 0; i < (int)(SystemSettings::GUICONFIGDATA_NUMELEM); i++)
|
||||
systemSettingsData.GUIConfigData[i] = configData.UAVObject[i];
|
||||
|
||||
systemSettings->setData(systemSettingsData);
|
||||
systemSettings->updated();
|
||||
|
||||
//emit ConfigurationChanged();
|
||||
}
|
||||
|
||||
void VehicleConfig::ResetActuators(GUIConfigDataUnion* configData)
|
||||
{
|
||||
}
|
||||
QStringList VehicleConfig::getChannelDescriptions()
|
||||
{
|
||||
QStringList channelDesc;
|
||||
|
||||
// init a channel_numelem list of channel desc defaults
|
||||
for (int i=0; i < (int)(VehicleConfig::CHANNEL_NUMELEM); i++)
|
||||
{
|
||||
channelDesc.append(QString("-"));
|
||||
}
|
||||
return channelDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
Helper function:
|
||||
Sets the current index on supplied combobox to index
|
||||
if it is within bounds 0 <= index < combobox.count()
|
||||
*/
|
||||
void VehicleConfig::setComboCurrentIndex(QComboBox* box, int index)
|
||||
{
|
||||
Q_ASSERT(box);
|
||||
|
||||
if (index >= 0 && index < box->count())
|
||||
box->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
Helper function:
|
||||
enables/disables the named combobox within supplied uiowner
|
||||
*/
|
||||
void VehicleConfig::enableComboBox(QWidget* owner, QString boxName, bool enable)
|
||||
{
|
||||
QComboBox* box = qFindChild<QComboBox*>(owner, boxName);
|
||||
if (box)
|
||||
box->setEnabled(enable);
|
||||
}
|
||||
|
||||
QString VehicleConfig::getMixerType(UAVDataObject* mixer, int channel)
|
||||
{
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
QString mixerType = mixerTypeDescriptions[0]; //default to disabled
|
||||
|
||||
if (channel >= 0 && channel < mixerTypes.count()) {
|
||||
UAVObjectField *field = mixer->getField(mixerTypes.at(channel));
|
||||
Q_ASSERT(field);
|
||||
|
||||
if (field)
|
||||
mixerType = field->getValue().toString();
|
||||
}
|
||||
|
||||
return mixerType;
|
||||
}
|
||||
|
||||
void VehicleConfig::setMixerType(UAVDataObject* mixer, int channel, MixerTypeElem mixerType)
|
||||
{
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
qDebug() << QString("setMixerType channel %0, type %1").arg(channel).arg(mixerType);
|
||||
|
||||
if (channel >= 0 && channel < mixerTypes.count()) {
|
||||
UAVObjectField *field = mixer->getField(mixerTypes.at(channel));
|
||||
Q_ASSERT(field);
|
||||
|
||||
if (field) {
|
||||
if (mixerType >= 0 && mixerType < mixerTypeDescriptions.count())
|
||||
{
|
||||
field->setValue(mixerTypeDescriptions[mixerType]);
|
||||
mixer->updated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VehicleConfig::resetMixerVector(UAVDataObject* mixer, int channel)
|
||||
{
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
if (channel >= 0 && channel < mixerVectors.count()) {
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE1, 0);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_THROTTLECURVE2, 0);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_PITCH, 0);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_ROLL, 0);
|
||||
setMixerVectorValue(mixer, channel, VehicleConfig::MIXERVECTOR_YAW, 0);
|
||||
}
|
||||
}
|
||||
|
||||
double VehicleConfig::getMixerVectorValue(UAVDataObject* mixer, int channel, MixerVectorElem elementName)
|
||||
{
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
double value = 0;
|
||||
|
||||
if (channel >= 0 && channel < mixerVectors.count()) {
|
||||
UAVObjectField *field = mixer->getField(mixerVectors.at(channel));
|
||||
Q_ASSERT(field);
|
||||
|
||||
if (field) {
|
||||
value = field->getDouble(elementName);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void VehicleConfig::setMixerVectorValue(UAVDataObject* mixer, int channel, MixerVectorElem elementName, double value)
|
||||
{
|
||||
Q_ASSERT(mixer);
|
||||
|
||||
qDebug() << QString("setMixerVectorValue channel %0, name %1, value %2").arg(channel).arg(elementName).arg(value);
|
||||
|
||||
if (channel >= 0 && channel < mixerVectors.count()) {
|
||||
UAVObjectField *field = mixer->getField(mixerVectors.at(channel));
|
||||
Q_ASSERT(field);
|
||||
|
||||
if (field) {
|
||||
field->setDouble(value, elementName);
|
||||
mixer->updated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Reset the contents of a field
|
||||
*/
|
||||
void VehicleConfig::resetField(UAVObjectField * field)
|
||||
{
|
||||
for (unsigned int i=0;i<field->getNumElements();i++) {
|
||||
field->setValue(0,i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Util function to get a pointer to the object manager
|
||||
* @return pointer to the UAVObjectManager
|
||||
*/
|
||||
UAVObjectManager* VehicleConfig::getUAVObjectManager() {
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager * objMngr = pm->getObject<UAVObjectManager>();
|
||||
Q_ASSERT(objMngr);
|
||||
return objMngr;
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file vehicleconfig.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup ConfigPlugin Config Plugin
|
||||
* @{
|
||||
* @brief bit storage of config ui settings
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef GUIVEHICLECONFIG_H
|
||||
#define GUIVEHICLECONFIG_H
|
||||
|
||||
#include "../uavobjectwidgetutils/configtaskwidget.h"
|
||||
#include "extensionsystem/pluginmanager.h"
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint VTOLMotorN:4;
|
||||
uint VTOLMotorS:4;
|
||||
uint VTOLMotorE:4;
|
||||
uint VTOLMotorW:4;
|
||||
uint VTOLMotorNW:4;
|
||||
uint VTOLMotorNE:4;
|
||||
uint VTOLMotorSW:4;
|
||||
uint VTOLMotorSE:4; //32bits
|
||||
uint TRIYaw:4;
|
||||
quint32 padding:28; //64bits
|
||||
quint32 padding1;
|
||||
quint32 padding2; //128bits
|
||||
} __attribute__((packed)) multiGUISettingsStruct;
|
||||
|
||||
typedef struct {
|
||||
uint SwashplateType:3;
|
||||
uint FirstServoIndex:2;
|
||||
uint CorrectionAngle:9;
|
||||
uint ccpmCollectivePassthroughState:1;
|
||||
uint ccpmLinkCyclicState:1;
|
||||
uint ccpmLinkRollState:1;
|
||||
uint SliderValue0:7;
|
||||
uint SliderValue1:7;
|
||||
uint SliderValue2:7;//41bits
|
||||
uint ServoIndexW:4;
|
||||
uint ServoIndexX:4;
|
||||
uint ServoIndexY:4;
|
||||
uint ServoIndexZ:4;//57bits
|
||||
uint Throttle:4;
|
||||
uint Tail:4; //65bits
|
||||
quint32 padding:31; //96bits
|
||||
quint32 padding1; //128bits
|
||||
} __attribute__((packed)) heliGUISettingsStruct;
|
||||
|
||||
typedef struct {
|
||||
uint FixedWingThrottle:4;
|
||||
uint FixedWingRoll1:4;
|
||||
uint FixedWingRoll2:4;
|
||||
uint FixedWingPitch1:4;
|
||||
uint FixedWingPitch2:4;
|
||||
uint FixedWingYaw1:4;
|
||||
uint FixedWingYaw2:4;
|
||||
uint padding:4; //32bits
|
||||
quint32 padding1;
|
||||
quint32 padding2;
|
||||
quint32 padding3; //128bits
|
||||
} __attribute__((packed)) fixedGUISettingsStruct;
|
||||
|
||||
typedef struct {
|
||||
uint GroundVehicleThrottle1:4;
|
||||
uint GroundVehicleThrottle2:4;
|
||||
uint GroundVehicleSteering1:4;
|
||||
uint GroundVehicleSteering2:4;
|
||||
uint padding:16; //32bits
|
||||
quint32 padding1;
|
||||
quint32 padding2;
|
||||
quint32 padding3; //128bits
|
||||
} __attribute__((packed)) groundGUISettingsStruct;
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint UAVObject[4]; //32bits * 4
|
||||
heliGUISettingsStruct heli; //128bits
|
||||
fixedGUISettingsStruct fixedwing;
|
||||
multiGUISettingsStruct multi;
|
||||
groundGUISettingsStruct ground;
|
||||
} GUIConfigDataUnion;
|
||||
|
||||
|
||||
class VehicleConfig: public ConfigTaskWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VehicleConfig(QWidget *parent = 0);
|
||||
~VehicleConfig();
|
||||
|
||||
/* Enumeration options for field MixerType */
|
||||
typedef enum { MIXERTYPE_DISABLED=0, MIXERTYPE_MOTOR=1, MIXERTYPE_SERVO=2, MIXERTYPE_CAMERAROLL=3, MIXERTYPE_CAMERAPITCH=4, MIXERTYPE_CAMERAYAW=5, MIXERTYPE_ACCESSORY0=6, MIXERTYPE_ACCESSORY1=7, MIXERTYPE_ACCESSORY2=8, MIXERTYPE_ACCESSORY3=9, MIXERTYPE_ACCESSORY4=10, MIXERTYPE_ACCESSORY5=11 } MixerTypeElem;
|
||||
/* Array element names for field MixerVector */
|
||||
typedef enum { MIXERVECTOR_THROTTLECURVE1=0, MIXERVECTOR_THROTTLECURVE2=1, MIXERVECTOR_ROLL=2, MIXERVECTOR_PITCH=3, MIXERVECTOR_YAW=4 } MixerVectorElem;
|
||||
|
||||
static GUIConfigDataUnion GetConfigData();
|
||||
static void SetConfigData(GUIConfigDataUnion configData);
|
||||
static void resetField(UAVObjectField * field);
|
||||
static void setComboCurrentIndex(QComboBox* box, int index);
|
||||
static void enableComboBox(QWidget* owner, QString boxName, bool enable);
|
||||
|
||||
double getMixerVectorValue(UAVDataObject* mixer, int channel, MixerVectorElem elementName);
|
||||
void setMixerVectorValue(UAVDataObject* mixer, int channel, MixerVectorElem elementName, double value);
|
||||
void resetMixerVector(UAVDataObject* mixer, int channel);
|
||||
QString getMixerType(UAVDataObject* mixer, int channel);
|
||||
void setMixerType(UAVDataObject* mixer, int channel, MixerTypeElem mixerType);
|
||||
|
||||
virtual void ResetActuators(GUIConfigDataUnion* configData);
|
||||
virtual QStringList getChannelDescriptions();
|
||||
|
||||
QStringList channelNames;
|
||||
QStringList mixerTypes;
|
||||
QStringList mixerVectors;
|
||||
QStringList mixerTypeDescriptions;
|
||||
|
||||
static const quint32 CHANNEL_NUMELEM = 10;
|
||||
|
||||
private:
|
||||
|
||||
static UAVObjectManager* getUAVObjectManager();
|
||||
|
||||
private slots:
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
//void ConfigurationChanged();
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
#endif // GUIVEHICLECONFIG_H
|
@ -30,7 +30,11 @@ HEADERS += configplugin.h \
|
||||
inputchannelform.h \
|
||||
configcamerastabilizationwidget.h \
|
||||
configtxpidwidget.h \
|
||||
outputchannelform.h \
|
||||
outputchannelform.h \
|
||||
cfg_vehicletypes/configmultirotorwidget.h \
|
||||
cfg_vehicletypes/configgroundvehiclewidget.h \
|
||||
cfg_vehicletypes/configfixedwingwidget.h \
|
||||
cfg_vehicletypes/vehicleconfig.h \
|
||||
configrevowidget.h \
|
||||
config_global.h
|
||||
SOURCES += configplugin.cpp \
|
||||
@ -62,7 +66,8 @@ SOURCES += configplugin.cpp \
|
||||
cfg_vehicletypes/configgroundvehiclewidget.cpp \
|
||||
cfg_vehicletypes/configfixedwingwidget.cpp \
|
||||
cfg_vehicletypes/configccpmwidget.cpp \
|
||||
outputchannelform.cpp
|
||||
outputchannelform.cpp \
|
||||
cfg_vehicletypes/vehicleconfig.cpp
|
||||
FORMS += airframe.ui \
|
||||
cc_hw_settings.ui \
|
||||
pro_hw_settings.ui \
|
||||
|
@ -33,8 +33,8 @@
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <accels.h>
|
||||
#include <gyros.h>
|
||||
#include "accels.h"
|
||||
#include "gyros.h"
|
||||
|
||||
ConfigCCAttitudeWidget::ConfigCCAttitudeWidget(QWidget *parent) :
|
||||
ConfigTaskWidget(parent),
|
||||
@ -107,7 +107,6 @@ void ConfigCCAttitudeWidget::accelsUpdated(UAVObject * obj) {
|
||||
attitudeSettingsData.GyroBias[2] = -z_gyro_bias;
|
||||
attitudeSettingsData.BiasCorrectGyro = AttitudeSettings::BIASCORRECTGYRO_TRUE;
|
||||
AttitudeSettings::GetInstance(getObjectManager())->setData(attitudeSettingsData);
|
||||
|
||||
} else {
|
||||
// Possible to get here if weird threading stuff happens. Just ignore updates.
|
||||
qDebug("Unexpected accel update received.");
|
||||
@ -174,3 +173,10 @@ void ConfigCCAttitudeWidget::enableControls(bool enable)
|
||||
ConfigTaskWidget::enableControls(enable);
|
||||
|
||||
}
|
||||
|
||||
void ConfigCCAttitudeWidget::updateObjectsFromWidgets()
|
||||
{
|
||||
ConfigTaskWidget::updateObjectsFromWidgets();
|
||||
|
||||
ui->zeroBiasProgress->setValue(0);
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
explicit ConfigCCAttitudeWidget(QWidget *parent = 0);
|
||||
~ConfigCCAttitudeWidget();
|
||||
|
||||
virtual void updateObjectsFromWidgets();
|
||||
|
||||
private slots:
|
||||
void accelsUpdated(UAVObject * obj);
|
||||
void timeout();
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "configoutputwidget.h"
|
||||
#include "outputchannelform.h"
|
||||
#include "configvehicletypewidget.h"
|
||||
|
||||
#include "uavtalk/telemetrymanager.h"
|
||||
|
||||
@ -39,9 +40,11 @@
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include "mixersettings.h"
|
||||
#include "actuatorcommand.h"
|
||||
#include "actuatorsettings.h"
|
||||
#include "systemalarms.h"
|
||||
#include "systemsettings.h"
|
||||
#include "uavsettingsimportexport/uavsettingsimportexportfactory.h"
|
||||
|
||||
ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(parent),wasItMe(false)
|
||||
@ -231,35 +234,35 @@ void ConfigOutputWidget::sendChannelTest(int index, int value)
|
||||
/**
|
||||
Request the current config from the board (RC Output)
|
||||
*/
|
||||
void ConfigOutputWidget::refreshOutputWidgetsValues(UAVObject *)
|
||||
void ConfigOutputWidget::refreshWidgetsValues(UAVObject * obj)
|
||||
{
|
||||
// Reset all channel assignements:
|
||||
QList<OutputChannelForm*> outputChannelForms = findChildren<OutputChannelForm*>();
|
||||
foreach(OutputChannelForm *outputChannelForm, outputChannelForms)
|
||||
{
|
||||
outputChannelForm->setAssignment("-");
|
||||
}
|
||||
Q_UNUSED(obj);
|
||||
|
||||
// FIXME: Use static accessor method for retrieving channel assignments
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
Q_ASSERT(pm);
|
||||
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
|
||||
Q_ASSERT(objManager);
|
||||
|
||||
// Get the channel assignements:
|
||||
UAVDataObject * obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
QList<UAVObjectField*> fieldList = obj->getFields();
|
||||
foreach (UAVObjectField* field, fieldList) {
|
||||
if (field->getUnits().contains("channel")) {
|
||||
assignOutputChannel(obj,field->getName());
|
||||
}
|
||||
}
|
||||
bool dirty=isDirty();
|
||||
|
||||
// Get Actuator Settings
|
||||
ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager());
|
||||
Q_ASSERT(actuatorSettings);
|
||||
ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData();
|
||||
|
||||
// get channel descriptions
|
||||
QStringList ChannelDesc = ConfigVehicleTypeWidget::getChannelDescriptions();
|
||||
|
||||
// Initialize output forms
|
||||
QList<OutputChannelForm*> outputChannelForms = findChildren<OutputChannelForm*>();
|
||||
foreach(OutputChannelForm *outputChannelForm, outputChannelForms)
|
||||
{
|
||||
outputChannelForm->setAssignment(ChannelDesc[outputChannelForm->index()]);
|
||||
|
||||
// init min,max,neutral
|
||||
int minValue = actuatorSettingsData.ChannelMin[outputChannelForm->index()];
|
||||
int maxValue = actuatorSettingsData.ChannelMax[outputChannelForm->index()];
|
||||
outputChannelForm->minmax(minValue, maxValue);
|
||||
|
||||
int neutral = actuatorSettingsData.ChannelNeutral[outputChannelForm->index()];
|
||||
outputChannelForm->neutral(neutral);
|
||||
}
|
||||
|
||||
// Get the SpinWhileArmed setting
|
||||
m_config->spinningArmed->setChecked(actuatorSettingsData.MotorsSpinWhileArmed == ActuatorSettings::MOTORSSPINWHILEARMED_TRUE);
|
||||
|
||||
@ -275,6 +278,8 @@ void ConfigOutputWidget::refreshOutputWidgetsValues(UAVObject *)
|
||||
m_config->cb_outputRate1->setCurrentIndex(m_config->cb_outputRate1->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[0])));
|
||||
m_config->cb_outputRate2->setCurrentIndex(m_config->cb_outputRate2->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[1])));
|
||||
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
Q_ASSERT(pm);
|
||||
UAVObjectUtilManager* utilMngr = pm->getObject<UAVObjectUtilManager>();
|
||||
if (utilMngr) {
|
||||
int board = utilMngr->getBoardModel();
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
#include "uavobjectutilmanager.h"
|
||||
#include "cfg_vehicletypes/vehicleconfig.h"
|
||||
#include <QtGui/QWidget>
|
||||
#include <QList>
|
||||
|
||||
@ -57,8 +58,7 @@ private:
|
||||
|
||||
void assignChannel(UAVDataObject *obj, QString str);
|
||||
void assignOutputChannel(UAVDataObject *obj, QString str);
|
||||
OutputChannelForm* getOutputChannelForm(const int index) const;
|
||||
|
||||
OutputChannelForm* getOutputChannelForm(const int index) const;
|
||||
int mccDataRate;
|
||||
|
||||
UAVObject::Metadata accInitialData;
|
||||
@ -69,7 +69,7 @@ private:
|
||||
private slots:
|
||||
void stopTests();
|
||||
void disableIfNotMe(UAVObject *obj);
|
||||
void refreshOutputWidgetsValues(UAVObject * obj = NULL);
|
||||
virtual void refreshWidgetsValues(UAVObject * obj=NULL);
|
||||
void updateObjectsFromWidgets();
|
||||
void runChannelTests(bool state);
|
||||
void sendChannelTest(int index, int value);
|
||||
|
@ -103,22 +103,22 @@ ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWi
|
||||
addUAVObject("MixerSettings");
|
||||
addUAVObject("ActuatorSettings");
|
||||
|
||||
|
||||
ffTuningInProgress = false;
|
||||
ffTuningPhase = false;
|
||||
|
||||
//Generate list of channels
|
||||
QStringList channels;
|
||||
channels << "None";
|
||||
for (unsigned int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) {
|
||||
//Generate lists of mixerTypeNames, mixerVectorNames, channelNames
|
||||
channelNames << "None";
|
||||
for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) {
|
||||
|
||||
mixerTypes << QString("Mixer%1Type").arg(i+1);
|
||||
mixerVectors << QString("Mixer%1Vector").arg(i+1);
|
||||
channels << QString("Channel%1").arg(i+1);
|
||||
channelNames << QString("Channel%1").arg(i+1);
|
||||
}
|
||||
|
||||
QStringList airframeTypes;
|
||||
airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Ground" << "Custom";
|
||||
m_aircraft->aircraftType->addItems(airframeTypes);
|
||||
|
||||
m_aircraft->aircraftType->setCurrentIndex(0); //Set default vehicle to Fixed Wing
|
||||
|
||||
QStringList fixedWingTypes;
|
||||
@ -138,27 +138,13 @@ ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWi
|
||||
m_aircraft->multirotorFrameType->addItems(multiRotorTypes);
|
||||
m_aircraft->multirotorFrameType->setCurrentIndex(1); //Set default model to "Quad +"
|
||||
|
||||
// Now load all the channel assignements
|
||||
//OLD STYLE: DO IT MANUALLY
|
||||
// m_aircraft->triYawChannelBox->addItems(channels);
|
||||
// m_aircraft->gvMotor1ChannelBox->addItems(channels);
|
||||
// m_aircraft->gvMotor2ChannelBox->addItems(channels);
|
||||
// m_aircraft->gvSteering1ChannelBox->addItems(channels);
|
||||
// m_aircraft->gvSteering2ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwElevator1ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwElevator2ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwEngineChannelBox->addItems(channels);
|
||||
// m_aircraft->fwRudder1ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwRudder2ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwAileron1ChannelBox->addItems(channels);
|
||||
// m_aircraft->fwAileron2ChannelBox->addItems(channels);
|
||||
|
||||
//NEW STYLE: Loop through the widgets looking for all widgets that have "ChannelBox" in their name
|
||||
// The upshot of this is that ALL new ComboBox widgets for selecting the output channel must have "ChannelBox" in their name
|
||||
foreach(QComboBox *combobox, this->findChildren<QComboBox*>(QRegExp("\\S+ChannelBo\\S+")))//FOR WHATEVER REASON, THIS DOES NOT WORK WITH ChannelBox. ChannelBo is sufficiently accurate
|
||||
{
|
||||
combobox->addItems(channels);
|
||||
}
|
||||
combobox->addItems(channelNames);
|
||||
}
|
||||
|
||||
// Setup the Multirotor picture in the Quad settings interface
|
||||
m_aircraft->quadShape->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
@ -188,6 +174,27 @@ ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWi
|
||||
m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd);
|
||||
}
|
||||
|
||||
// create and setup a MultiRotor config widget
|
||||
m_multirotor = new ConfigMultiRotorWidget(m_aircraft);
|
||||
m_multirotor->quad = quad;
|
||||
m_multirotor->uiowner = this;
|
||||
m_multirotor->setupUI(m_aircraft->multirotorFrameType->currentText());
|
||||
|
||||
// create and setup a GroundVehicle config widget
|
||||
m_groundvehicle = new ConfigGroundVehicleWidget(m_aircraft);
|
||||
m_groundvehicle->setupUI(m_aircraft->groundVehicleType->currentText() );
|
||||
|
||||
// create and setup a FixedWing config widget
|
||||
m_fixedwing = new ConfigFixedWingWidget(m_aircraft);
|
||||
m_fixedwing->setupUI(m_aircraft->fixedWingType->currentText() );
|
||||
|
||||
// create and setup a Helicopter config widget
|
||||
m_heli = m_aircraft->widget_3;
|
||||
m_heli->setupUI(QString("HeliCP"));
|
||||
|
||||
// initialize the ui to show the mixersettings tab
|
||||
//mdl m_aircraft->tabWidget->setCurrentIndex(0);
|
||||
|
||||
//Connect aircraft type selection dropbox to callback function
|
||||
connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int)));
|
||||
|
||||
@ -195,6 +202,7 @@ ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWi
|
||||
connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
connect(m_aircraft->groundVehicleType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
//mdl connect(m_heli->m_ccpm->ccpmType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
|
||||
|
||||
//Connect throttle curve reset pushbuttons to reset functions
|
||||
connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer()));
|
||||
@ -220,19 +228,12 @@ ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWi
|
||||
connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
|
||||
|
||||
//WHAT DOES THIS DO?
|
||||
enableControls(false);
|
||||
refreshWidgetsValues();
|
||||
|
||||
// Connect the help pushbutton
|
||||
connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
|
||||
enableControls(false);
|
||||
refreshWidgetsValues();
|
||||
addToDirtyMonitor();
|
||||
|
||||
//Initialize GUI tabs //MOVING THIS FROM THE END OF THIS FUNCTION CAN CAUSE RUNTIME ERRORS DUE TO setupMultiRotorUI. WHY?
|
||||
setupMultiRotorUI( m_aircraft->multirotorFrameType->currentText() );
|
||||
setupGroundVehicleUI( m_aircraft->groundVehicleType->currentText() );
|
||||
setupFixedWingUI( m_aircraft->fixedWingType->currentText() );
|
||||
|
||||
|
||||
disableMouseWheelEvents();
|
||||
}
|
||||
|
||||
@ -245,12 +246,95 @@ ConfigVehicleTypeWidget::~ConfigVehicleTypeWidget()
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
Static function to get currently assigned channelDescriptions
|
||||
for all known vehicle types; instantiates the appropriate object
|
||||
then asks it to supply channel descs
|
||||
*/
|
||||
QStringList ConfigVehicleTypeWidget::getChannelDescriptions()
|
||||
{
|
||||
int i;
|
||||
QStringList channelDesc;
|
||||
|
||||
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
|
||||
UAVObjectManager * objMngr = pm->getObject<UAVObjectManager>();
|
||||
Q_ASSERT(objMngr);
|
||||
|
||||
// get an instance of systemsettings
|
||||
SystemSettings * systemSettings = SystemSettings::GetInstance(objMngr);
|
||||
Q_ASSERT(systemSettings);
|
||||
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
|
||||
|
||||
switch (systemSettingsData.AirframeType)
|
||||
{
|
||||
// fixed wing
|
||||
case SystemSettings::AIRFRAMETYPE_FIXEDWING:
|
||||
case SystemSettings::AIRFRAMETYPE_FIXEDWINGELEVON:
|
||||
case SystemSettings::AIRFRAMETYPE_FIXEDWINGVTAIL:
|
||||
{
|
||||
ConfigFixedWingWidget* fixedwing = new ConfigFixedWingWidget();
|
||||
channelDesc = fixedwing->getChannelDescriptions();
|
||||
}
|
||||
break;
|
||||
|
||||
// helicp
|
||||
case SystemSettings::AIRFRAMETYPE_HELICP:
|
||||
{
|
||||
ConfigCcpmWidget* heli = new ConfigCcpmWidget();
|
||||
channelDesc = heli->getChannelDescriptions();
|
||||
}
|
||||
break;
|
||||
|
||||
//multirotor
|
||||
case SystemSettings::AIRFRAMETYPE_VTOL:
|
||||
case SystemSettings::AIRFRAMETYPE_TRI:
|
||||
case SystemSettings::AIRFRAMETYPE_QUADX:
|
||||
case SystemSettings::AIRFRAMETYPE_QUADP:
|
||||
case SystemSettings::AIRFRAMETYPE_OCTOV:
|
||||
case SystemSettings::AIRFRAMETYPE_OCTOCOAXX:
|
||||
case SystemSettings::AIRFRAMETYPE_OCTOCOAXP:
|
||||
case SystemSettings::AIRFRAMETYPE_OCTO:
|
||||
case SystemSettings::AIRFRAMETYPE_HEXAX:
|
||||
case SystemSettings::AIRFRAMETYPE_HEXACOAX:
|
||||
case SystemSettings::AIRFRAMETYPE_HEXA:
|
||||
{
|
||||
ConfigMultiRotorWidget* multi = new ConfigMultiRotorWidget();
|
||||
channelDesc = multi->getChannelDescriptions();
|
||||
}
|
||||
break;
|
||||
|
||||
// ground
|
||||
case SystemSettings::AIRFRAMETYPE_GROUNDVEHICLECAR:
|
||||
case SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEDIFFERENTIAL:
|
||||
case SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEMOTORCYCLE:
|
||||
{
|
||||
ConfigGroundVehicleWidget* ground = new ConfigGroundVehicleWidget();
|
||||
channelDesc = ground->getChannelDescriptions();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
for (i=0; i < (int)(VehicleConfig::CHANNEL_NUMELEM); i++)
|
||||
channelDesc.append(QString("-"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// for (i=0; i < channelDesc.count(); i++)
|
||||
// qDebug() << QString("Channel %0 = %1").arg(i).arg(channelDesc[i]);
|
||||
|
||||
return channelDesc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Slot for switching the airframe type. We do it explicitely
|
||||
rather than a signal in the UI, because we want to force a fitInView of the quad shapes.
|
||||
This is because this method (fitinview) only works when the widget is shown.
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::switchAirframeType(int index){
|
||||
void ConfigVehicleTypeWidget::switchAirframeType(int index)
|
||||
{
|
||||
m_aircraft->airframesWidget->setCurrentIndex(index);
|
||||
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
|
||||
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
|
||||
@ -331,7 +415,6 @@ void ConfigVehicleTypeWidget::toggleRudder2(int index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
/// Feed Forward Testing
|
||||
/////////////////////////////////////////////////////////
|
||||
@ -525,8 +608,10 @@ void ConfigVehicleTypeWidget::updateCustomThrottle2CurveValue(QList<double> list
|
||||
/**
|
||||
Refreshes the current value of the SystemSettings which holds the aircraft type
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::refreshWidgetsValues(UAVObject *)
|
||||
void ConfigVehicleTypeWidget::refreshWidgetsValues(UAVObject * o)
|
||||
{
|
||||
Q_UNUSED(o);
|
||||
|
||||
if(!allObjectsUpdated())
|
||||
return;
|
||||
|
||||
@ -609,7 +694,7 @@ void ConfigVehicleTypeWidget::refreshWidgetsValues(UAVObject *)
|
||||
if (frameType.startsWith("FixedWing")) {
|
||||
|
||||
// Retrieve fixed wing settings
|
||||
refreshFixedWingWidgetsValues(frameType);
|
||||
m_fixedwing->refreshWidgetsValues(frameType);
|
||||
|
||||
} else if (frameType == "Tri" ||
|
||||
frameType == "QuadX" || frameType == "QuadP" ||
|
||||
@ -617,17 +702,18 @@ void ConfigVehicleTypeWidget::refreshWidgetsValues(UAVObject *)
|
||||
frameType == "Octo" || frameType == "OctoV" || frameType == "OctoCoaxP" || frameType == "OctoCoaxX" ) {
|
||||
|
||||
// Retrieve multirotor settings
|
||||
refreshMultiRotorWidgetsValues(frameType);
|
||||
m_multirotor->refreshWidgetsValues(frameType);
|
||||
} else if (frameType == "HeliCP") {
|
||||
m_aircraft->widget_3->requestccpmUpdate();
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Helicopter"));//"Helicopter"
|
||||
setComboCurrentIndex(m_aircraft->aircraftType, m_aircraft->aircraftType->findText("Helicopter"));
|
||||
m_heli->refreshWidgetsValues(frameType);
|
||||
|
||||
} else if (frameType.startsWith("GroundVehicle")) {
|
||||
|
||||
// Retrieve ground vehicle settings
|
||||
refreshGroundVehicleWidgetsValues(frameType);
|
||||
// Retrieve ground vehicle settings
|
||||
m_groundvehicle->refreshWidgetsValues(frameType);
|
||||
|
||||
} else if (frameType == "Custom") {
|
||||
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Custom"));
|
||||
setComboCurrentIndex(m_aircraft->aircraftType, m_aircraft->aircraftType->findText("Custom"));
|
||||
}
|
||||
|
||||
|
||||
@ -641,13 +727,13 @@ void ConfigVehicleTypeWidget::refreshWidgetsValues(UAVObject *)
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setupAirframeUI(QString frameType)
|
||||
{
|
||||
|
||||
bool dirty=isDirty();
|
||||
if(frameType == "FixedWing" || frameType == "Elevator aileron rudder" ||
|
||||
frameType == "FixedWingElevon" || frameType == "Elevon" ||
|
||||
frameType == "FixedWingVtail" || frameType == "Vtail"){
|
||||
setupFixedWingUI(frameType);
|
||||
} else if (frameType == "Tri" || frameType == "Tricopter Y" ||
|
||||
frameType == "FixedWingVtail" || frameType == "Vtail"){
|
||||
m_fixedwing->setupUI(frameType);
|
||||
}
|
||||
else if (frameType == "Tri" || frameType == "Tricopter Y" ||
|
||||
frameType == "QuadX" || frameType == "Quad X" ||
|
||||
frameType == "QuadP" || frameType == "Quad +" ||
|
||||
frameType == "Hexa" || frameType == "Hexacopter" ||
|
||||
@ -658,13 +744,16 @@ void ConfigVehicleTypeWidget::setupAirframeUI(QString frameType)
|
||||
frameType == "OctoCoaxP" || frameType == "Octo Coax +" ||
|
||||
frameType == "OctoCoaxX" || frameType == "Octo Coax X" ) {
|
||||
|
||||
//Call multi-rotor setup UI
|
||||
setupMultiRotorUI(frameType);
|
||||
//Call multi-rotor setup UI
|
||||
m_multirotor->setupUI(frameType);
|
||||
}
|
||||
else if (frameType == "HeliCP") {
|
||||
m_heli->setupUI(frameType);
|
||||
}
|
||||
else if (frameType == "GroundVehicleCar" || frameType == "Turnable (car)" ||
|
||||
frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)" ||
|
||||
frameType == "GroundVehicleMotorcyle" || frameType == "Motorcycle") {
|
||||
setupGroundVehicleUI(frameType);
|
||||
frameType == "GroundVehicleMotorcyle" || frameType == "Motorcycle") {
|
||||
m_groundvehicle->setupUI(frameType);
|
||||
}
|
||||
|
||||
//SHOULDN'T THIS BE DONE ONLY IN QUAD SETUP, AND NOT ALL THE REST???
|
||||
@ -685,26 +774,6 @@ void ConfigVehicleTypeWidget::resetField(UAVObjectField * field)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reset actuator values
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::resetActuators()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
|
||||
Q_ASSERT(obj);
|
||||
QList<UAVObjectField*> fieldList = obj->getFields();
|
||||
// Reset all assignements first:
|
||||
foreach (UAVObjectField* field, fieldList) {
|
||||
// NOTE: we assume that all options in ActuatorSettings are a channel assignement
|
||||
// except for the options called "ChannelBoxXXX"
|
||||
if (field->getUnits().contains("channel")) {
|
||||
field->setValue(field->getOptions().last());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Updates the custom airframe settings based on the current airframe.
|
||||
|
||||
@ -712,58 +781,77 @@ void ConfigVehicleTypeWidget::resetActuators()
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateCustomAirframeUI()
|
||||
{
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
QList<double> curveValues;
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
} else {
|
||||
double temp=0;
|
||||
double value;
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
value=field->getValue(i).toDouble();
|
||||
temp+=value;
|
||||
curveValues.append(value);
|
||||
}
|
||||
if(temp==0)
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
Q_ASSERT(obj);
|
||||
|
||||
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
|
||||
if (field)
|
||||
{
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
else
|
||||
m_aircraft->customThrottle1Curve->initCurve(curveValues);
|
||||
}
|
||||
|
||||
field = obj->getField(QString("ThrottleCurve2"));
|
||||
curveValues.clear();
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
} else {
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
curveValues.append(field->getValue(i).toDouble());
|
||||
} else {
|
||||
double temp=0;
|
||||
double value;
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
value=field->getValue(i).toDouble();
|
||||
temp+=value;
|
||||
curveValues.append(value);
|
||||
}
|
||||
if(temp==0)
|
||||
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
else
|
||||
m_aircraft->customThrottle1Curve->initCurve(curveValues);
|
||||
}
|
||||
}
|
||||
|
||||
curveValues.clear();
|
||||
|
||||
field = obj->getField(QString("ThrottleCurve2"));
|
||||
if (field)
|
||||
{
|
||||
// If the 1st element of the curve is <= -10, then the curve
|
||||
// is a straight line (that's how the mixer works on the mainboard):
|
||||
if (field->getValue(0).toInt() <= -10) {
|
||||
m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1);
|
||||
} else {
|
||||
for (unsigned int i=0; i < field->getNumElements(); i++) {
|
||||
curveValues.append(field->getValue(i).toDouble());
|
||||
}
|
||||
m_aircraft->customThrottle2Curve->initCurve(curveValues);
|
||||
}
|
||||
m_aircraft->customThrottle2Curve->initCurve(curveValues);
|
||||
}
|
||||
|
||||
// Update the table:
|
||||
for (int i=0; i<8; i++) {
|
||||
field = obj->getField(mixerTypes.at(i));
|
||||
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
|
||||
QString s = field->getValue().toString();
|
||||
q->setCurrentIndex(q->findText(s));
|
||||
//bool en = (s != "Disabled");
|
||||
field = obj->getField(mixerVectors.at(i));
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString());
|
||||
if (field)
|
||||
{
|
||||
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
|
||||
if (q)
|
||||
{
|
||||
QString s = field->getValue().toString();
|
||||
setComboCurrentIndex(q, q->findText(s));
|
||||
}
|
||||
|
||||
field = obj->getField(mixerVectors.at(i));
|
||||
if (field)
|
||||
{
|
||||
int ti = field->getElementNames().indexOf("ThrottleCurve1");
|
||||
m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("ThrottleCurve2");
|
||||
m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Roll");
|
||||
m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Pitch");
|
||||
m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString());
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -777,23 +865,25 @@ void ConfigVehicleTypeWidget::updateCustomAirframeUI()
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::updateObjectsFromWidgets()
|
||||
{
|
||||
qDebug()<<"updateObjectsFromWidgets";
|
||||
UAVDataObject* obj;
|
||||
UAVObjectField* field;
|
||||
|
||||
QString airframeType = "Custom"; //Sets airframe type default to "Custom"
|
||||
if (m_aircraft->aircraftType->currentText() == "Fixed Wing") {
|
||||
airframeType = updateFixedWingObjectsFromWidgets();
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Multirotor") {
|
||||
//update the mixer
|
||||
airframeType = updateMultiRotorObjectsFromWidgets();
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Helicopter") {
|
||||
airframeType = "HeliCP";
|
||||
m_aircraft->widget_3->sendccpmUpdate();
|
||||
} else if (m_aircraft->aircraftType->currentText() == "Ground") {
|
||||
airframeType = updateGroundVehicleObjectsFromWidgets();
|
||||
} else {
|
||||
airframeType = "Custom";
|
||||
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("FeedForward"));
|
||||
airframeType = m_fixedwing->updateConfigObjectsFromWidgets();
|
||||
}
|
||||
else if (m_aircraft->aircraftType->currentText() == "Multirotor") {
|
||||
airframeType = m_multirotor->updateConfigObjectsFromWidgets();
|
||||
}
|
||||
else if (m_aircraft->aircraftType->currentText() == "Helicopter") {
|
||||
airframeType = m_heli->updateConfigObjectsFromWidgets();
|
||||
}
|
||||
else if (m_aircraft->aircraftType->currentText() == "Ground") {
|
||||
airframeType = m_groundvehicle->updateConfigObjectsFromWidgets();
|
||||
}
|
||||
else {
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
|
||||
field = obj->getField(QString("FeedForward"));
|
||||
|
||||
// Curve is also common to all quads:
|
||||
field = obj->getField("ThrottleCurve1");
|
||||
@ -826,14 +916,13 @@ void ConfigVehicleTypeWidget::updateObjectsFromWidgets()
|
||||
ti = field->getElementNames().indexOf("Yaw");
|
||||
field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//WHAT DOES THIS DO?
|
||||
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
UAVObjectField* field = obj->getField(QString("AirframeType"));
|
||||
// set the airframe type
|
||||
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
|
||||
field = obj->getField(QString("AirframeType"));
|
||||
field->setValue(airframeType);
|
||||
|
||||
updateCustomAirframeUI();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -845,6 +934,16 @@ void ConfigVehicleTypeWidget::openHelp()
|
||||
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) );
|
||||
}
|
||||
|
||||
/**
|
||||
Helper function:
|
||||
Sets the current index on supplied combobox to index
|
||||
if it is within bounds 0 <= index < combobox.count()
|
||||
*/
|
||||
void ConfigVehicleTypeWidget::setComboCurrentIndex(QComboBox* box, int index)
|
||||
{
|
||||
if (index >= 0 && index < box->count())
|
||||
box->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
WHAT DOES THIS DO???
|
||||
@ -873,6 +972,9 @@ void ConfigVehicleTypeWidget::addToDirtyMonitor()
|
||||
addWidget(m_aircraft->multiMotorChannelBox6);
|
||||
addWidget(m_aircraft->multiMotorChannelBox7);
|
||||
addWidget(m_aircraft->multiMotorChannelBox8);
|
||||
addWidget(m_aircraft->mrPitchMixLevel);
|
||||
addWidget(m_aircraft->mrRollMixLevel);
|
||||
addWidget(m_aircraft->mrYawMixLevel);
|
||||
addWidget(m_aircraft->triYawChannelBox);
|
||||
addWidget(m_aircraft->aircraftType);
|
||||
addWidget(m_aircraft->fwEngineChannelBox);
|
||||
@ -884,44 +986,44 @@ void ConfigVehicleTypeWidget::addToDirtyMonitor()
|
||||
addWidget(m_aircraft->fwRudder2ChannelBox);
|
||||
addWidget(m_aircraft->elevonSlider1);
|
||||
addWidget(m_aircraft->elevonSlider2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveType);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve);
|
||||
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable);
|
||||
addWidget(m_heli->m_ccpm->ccpmType);
|
||||
addWidget(m_heli->m_ccpm->ccpmTailChannel);
|
||||
addWidget(m_heli->m_ccpm->ccpmEngineChannel);
|
||||
addWidget(m_heli->m_ccpm->ccpmServoWChannel);
|
||||
addWidget(m_heli->m_ccpm->ccpmServoXChannel);
|
||||
addWidget(m_heli->m_ccpm->ccpmServoYChannel);
|
||||
addWidget(m_heli->m_ccpm->ccpmSingleServo);
|
||||
addWidget(m_heli->m_ccpm->ccpmServoZChannel);
|
||||
addWidget(m_heli->m_ccpm->ccpmAngleW);
|
||||
addWidget(m_heli->m_ccpm->ccpmAngleX);
|
||||
addWidget(m_heli->m_ccpm->ccpmCorrectionAngle);
|
||||
addWidget(m_heli->m_ccpm->ccpmAngleZ);
|
||||
addWidget(m_heli->m_ccpm->ccpmAngleY);
|
||||
addWidget(m_heli->m_ccpm->ccpmCollectivePassthrough);
|
||||
addWidget(m_heli->m_ccpm->ccpmLinkRoll);
|
||||
addWidget(m_heli->m_ccpm->ccpmLinkCyclic);
|
||||
addWidget(m_heli->m_ccpm->ccpmRevoSlider);
|
||||
addWidget(m_heli->m_ccpm->ccpmREVOspinBox);
|
||||
addWidget(m_heli->m_ccpm->ccpmCollectiveSlider);
|
||||
addWidget(m_heli->m_ccpm->ccpmCollectivespinBox);
|
||||
addWidget(m_heli->m_ccpm->ccpmCollectiveScale);
|
||||
addWidget(m_heli->m_ccpm->ccpmCollectiveScaleBox);
|
||||
addWidget(m_heli->m_ccpm->ccpmCyclicScale);
|
||||
addWidget(m_heli->m_ccpm->ccpmPitchScale);
|
||||
addWidget(m_heli->m_ccpm->ccpmPitchScaleBox);
|
||||
addWidget(m_heli->m_ccpm->ccpmRollScale);
|
||||
addWidget(m_heli->m_ccpm->ccpmRollScaleBox);
|
||||
addWidget(m_heli->m_ccpm->SwashLvlPositionSlider);
|
||||
addWidget(m_heli->m_ccpm->SwashLvlPositionSpinBox);
|
||||
addWidget(m_heli->m_ccpm->CurveType);
|
||||
addWidget(m_heli->m_ccpm->NumCurvePoints);
|
||||
addWidget(m_heli->m_ccpm->CurveValue1);
|
||||
addWidget(m_heli->m_ccpm->CurveValue2);
|
||||
addWidget(m_heli->m_ccpm->CurveValue3);
|
||||
addWidget(m_heli->m_ccpm->CurveToGenerate);
|
||||
addWidget(m_heli->m_ccpm->CurveSettings);
|
||||
addWidget(m_heli->m_ccpm->ThrottleCurve);
|
||||
addWidget(m_heli->m_ccpm->PitchCurve);
|
||||
addWidget(m_heli->m_ccpm->ccpmAdvancedSettingsTable);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,12 @@
|
||||
#include "uavobjectmanager.h"
|
||||
#include "uavobject.h"
|
||||
#include "uavtalk/telemetrymanager.h"
|
||||
|
||||
#include "cfg_vehicletypes/configccpmwidget.h"
|
||||
#include "cfg_vehicletypes/configfixedwingwidget.h"
|
||||
#include "cfg_vehicletypes/configmultirotorwidget.h"
|
||||
#include "cfg_vehicletypes/configgroundvehiclewidget.h"
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
#include <QList>
|
||||
#include <QItemDelegate>
|
||||
@ -47,54 +53,40 @@ public:
|
||||
ConfigVehicleTypeWidget(QWidget *parent = 0);
|
||||
~ConfigVehicleTypeWidget();
|
||||
|
||||
static QStringList getChannelDescriptions();
|
||||
|
||||
private:
|
||||
Ui_AircraftWidget *m_aircraft;
|
||||
bool setupFrameFixedWing(QString airframeType);
|
||||
bool setupFrameElevon(QString airframeType);
|
||||
bool setupFrameVtail(QString airframeType);
|
||||
bool setupQuad(bool pLayout);
|
||||
bool setupHexa(bool pLayout);
|
||||
bool setupOcto();
|
||||
bool setupGroundVehicleCar(QString airframeType);
|
||||
bool setupGroundVehicleDifferential(QString airframeType);
|
||||
bool setupGroundVehicleMotorcycle(QString airframeType);
|
||||
|
||||
ConfigCcpmWidget *m_heli;
|
||||
ConfigFixedWingWidget *m_fixedwing;
|
||||
ConfigMultiRotorWidget *m_multirotor;
|
||||
ConfigGroundVehicleWidget *m_groundvehicle;
|
||||
|
||||
void updateCustomAirframeUI();
|
||||
bool setupMultiRotorMixer(double mixerFactors[8][3]);
|
||||
void setupMotors(QList<QString> motorList);
|
||||
void addToDirtyMonitor();
|
||||
void resetField(UAVObjectField * field);
|
||||
void resetMixer (MixerCurveWidget *mixer, int numElements, double maxvalue);
|
||||
void resetActuators();
|
||||
//void setMixerChannel(int channelNumber, bool channelIsMotor, QList<double> vector);
|
||||
void setupQuadMotor(int channel, double roll, double pitch, double yaw);
|
||||
|
||||
//void setMixerChannel(int channelNumber, bool channelIsMotor, QList<double> vector);
|
||||
|
||||
QStringList channelNames;
|
||||
QStringList mixerTypes;
|
||||
QStringList mixerVectors;
|
||||
|
||||
QGraphicsSvgItem *quad;
|
||||
bool ffTuningInProgress;
|
||||
bool ffTuningPhase;
|
||||
UAVObject::Metadata accInitialData;
|
||||
|
||||
private slots:
|
||||
virtual void refreshWidgetsValues(UAVObject * obj = NULL);
|
||||
void refreshFixedWingWidgetsValues(QString frameType);
|
||||
void refreshMultiRotorWidgetsValues(QString frameType);
|
||||
void refreshGroundVehicleWidgetsValues(QString frameType);
|
||||
|
||||
void updateObjectsFromWidgets();
|
||||
QString updateFixedWingObjectsFromWidgets();
|
||||
QString updateMultiRotorObjectsFromWidgets();
|
||||
QString updateGroundVehicleObjectsFromWidgets();
|
||||
// void saveAircraftUpdate();
|
||||
|
||||
virtual void refreshWidgetsValues(UAVObject * o=NULL);
|
||||
virtual void updateObjectsFromWidgets();
|
||||
|
||||
void setComboCurrentIndex(QComboBox* box, int index);
|
||||
|
||||
void setupAirframeUI(QString type);
|
||||
void setupFixedWingUI(QString frameType);
|
||||
void setupMultiRotorUI(QString frameType);
|
||||
void setupGroundVehicleUI(QString frameType);
|
||||
|
||||
void throwMultiRotorChannelConfigError(int numMotors);
|
||||
void throwFixedWingChannelConfigError(QString airframeType);
|
||||
void throwGroundVehicleChannelConfigError(QString airframeType);
|
||||
|
||||
void toggleAileron2(int index);
|
||||
void toggleElevator2(int index);
|
||||
|
@ -30,10 +30,11 @@ CLEAN_FLIGHT := YES
|
||||
endif
|
||||
|
||||
# Set up targets
|
||||
FW_TARGETS := $(addprefix fw_, coptercontrol) $(addprefix fw_, revolution)
|
||||
FW_TARGETS_TOOLS := $(addprefix fw_, coptercontrol)
|
||||
BL_TARGETS := $(addprefix bl_, coptercontrol)
|
||||
BU_TARGETS := $(addprefix bu_, coptercontrol)
|
||||
ALL_BOARDS := coptercontrol pipxtreme revolution
|
||||
FW_TARGETS := $(addprefix fw_, $(ALL_BOARDS))
|
||||
FW_TARGETS_TOOLS := $(addprefix fw_, $(ALL_BOARDS))
|
||||
BL_TARGETS := $(addprefix bl_, $(ALL_BOARDS))
|
||||
BU_TARGETS := $(addprefix bu_, $(ALL_BOARDS))
|
||||
|
||||
help:
|
||||
@echo
|
||||
|
@ -22,6 +22,8 @@ device=$(hdiutil attach "${TEMP_FILE}" | \
|
||||
cp -r "${APP_PATH}" "/Volumes/${VOL_NAME}"
|
||||
#cp -r "${FW_DIR}" "/Volumes/${VOL_NAME}/firmware"
|
||||
cp "${FW_DIR}/fw_coptercontrol-${PACKAGE_LBL}.opfw" "/Volumes/${VOL_NAME}/Firmware"
|
||||
cp "${FW_DIR}/fw_pipxtreme-${PACKAGE_LBL}.opfw" "/Volumes/${VOL_NAME}/Firmware"
|
||||
cp "${FW_DIR}/fw_revolution-${PACKAGE_LBL}.opfw" "/Volumes/${VOL_NAME}/Firmware"
|
||||
|
||||
cp "${BUILD_DIR}/uavobject-synthetics/matlab/OPLogConvert.m" "/Volumes/${VOL_NAME}/Utilities"
|
||||
|
||||
|
@ -1,25 +1,6 @@
|
||||
<xml>
|
||||
<object name="ActuatorSettings" singleinstance="true" settings="true">
|
||||
<description>Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType</description>
|
||||
<field name="FixedWingRoll1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingRoll2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingPitch1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingPitch2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingYaw1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingYaw2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="FixedWingThrottle" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorN" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorNE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorSE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorS" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorSW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="VTOLMotorNW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleThrottle1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleThrottle2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleSteering1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="GroundVehicleSteering2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
|
||||
<field name="ChannelUpdateFreq" units="Hz" type="uint16" elements="4" defaultvalue="50"/>
|
||||
<field name="ChannelMax" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
<field name="ChannelNeutral" units="us" type="int16" elements="10" defaultvalue="1000"/>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<object name="SystemSettings" singleinstance="true" settings="true">
|
||||
<description>Select airframe type. Currently used by @ref ActuatorModule to choose mixing from @ref ActuatorDesired to @ref ActuatorCommand</description>
|
||||
<field name="AirframeType" units="" type="enum" elements="1" options="FixedWing,FixedWingElevon,FixedWingVtail,VTOL,HeliCP,QuadX,QuadP,Hexa,Octo,Custom,HexaX,OctoV,OctoCoaxP,OctoCoaxX,HexaCoax,Tri,GroundVehicleCar,GroundVehicleDifferential,GroundVehicleMotorcycle" defaultvalue="FixedWing"/>
|
||||
<field name="GUIConfigData" units="bits" type="uint32" elements="2" defaultvalue="0"/>
|
||||
<field name="GUIConfigData" units="bits" type="uint32" elements="4" defaultvalue="0"/>
|
||||
<access gcs="readwrite" flight="readwrite"/>
|
||||
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
|
||||
<telemetryflight acked="true" updatemode="onchange" period="0"/>
|
||||
|
Loading…
Reference in New Issue
Block a user